diff options
| author | Jasper van de Gronde <jasper.vandegronde@gmail.com> | 2008-07-05 14:56:14 +0000 |
|---|---|---|
| committer | jaspervdg <jaspervdg@users.sourceforge.net> | 2008-07-05 14:56:14 +0000 |
| commit | 599560de99712f74762376ee73426e318fca6c65 (patch) | |
| tree | af78f529d8f639f7d879879f283272dab9389264 /src | |
| parent | widgets/select-toolbar.h: Supply missing #includes/declarations so that we do... (diff) | |
| download | inkscape-599560de99712f74762376ee73426e318fca6c65.tar.gz inkscape-599560de99712f74762376ee73426e318fca6c65.zip | |
Tests for nr-compose, as well as updated tests for svg-affine and svg-length.
(bzr r6192)
Diffstat (limited to 'src')
| -rw-r--r-- | src/libnr/nr-compose-reference.cpp | 266 | ||||
| -rw-r--r-- | src/libnr/nr-compose-reference.h | 69 | ||||
| -rw-r--r-- | src/libnr/nr-compose-test.h | 451 | ||||
| -rw-r--r-- | src/svg/svg-affine-test.h | 42 | ||||
| -rw-r--r-- | src/svg/svg-length-test.h | 111 |
5 files changed, 921 insertions, 18 deletions
diff --git a/src/libnr/nr-compose-reference.cpp b/src/libnr/nr-compose-reference.cpp new file mode 100644 index 000000000..b952939ed --- /dev/null +++ b/src/libnr/nr-compose-reference.cpp @@ -0,0 +1,266 @@ + +// This is a reference implementation of the compositing functions in nr-compose.cpp. + +#include "nr-compose-reference.h" + +#define NR_RGBA32_R(v) (unsigned char) (((v) >> 24) & 0xff) +#define NR_RGBA32_G(v) (unsigned char) (((v) >> 16) & 0xff) +#define NR_RGBA32_B(v) (unsigned char) (((v) >> 8) & 0xff) +#define NR_RGBA32_A(v) (unsigned char) ((v) & 0xff) + +static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; } + +static unsigned int pixelSize[] = { 1, 3, 4, 4 }; + +// Computes : +// dc' = (1 - alpha*sa) * dc + alpha*sc +// da' = 1 - (1 - alpha*sa) * (1 - da) +// Assuming premultiplied color values +template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> +static void composePixel(unsigned char *d, const unsigned char *s, unsigned int alpha); + +template<> static void composePixel<R8G8B8, R8G8B8, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255); +} + +template<> static void composePixel<R8G8B8, R8G8B8, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255*alpha*s[0], 255*255); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255*alpha*s[1], 255*255); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255*alpha*s[2], 255*255); +} + +template<> static void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + unsigned int newa = 255*255 - (255*255 - alpha*s[3]); + d[0] = s[0];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[0], newa); + d[1] = s[1];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[1], newa); + d[2] = s[2];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[2], newa); + d[3] = DIV_ROUND(newa, 255); +} + +template<> static void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + unsigned int newa = 255*255 - (255*255 - alpha*s[3]); + d[0] = s[3] == 0 ? 0 : DIV_ROUND(255*s[0], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[0], newa); + d[1] = s[3] == 0 ? 0 : DIV_ROUND(255*s[1], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[1], newa); + d[2] = s[3] == 0 ? 0 : DIV_ROUND(255*s[2], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[2], newa); + d[3] = DIV_ROUND(newa, 255); +} + +template<> static void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + if ( d[3] == 0 ) { + composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(d, s, alpha); + } else if ( alpha*s[3] == 0 ) { + /* NOP */ + } else { + unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]); + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255 * alpha*s[3]*s[0], newa); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255 * alpha*s[3]*s[1], newa); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255 * alpha*s[3]*s[2], newa); + d[3] = DIV_ROUND(newa, 255*255); + } +} + +template<> static void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + if ( d[3] == 0 ) { + composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(d, s, alpha); + } else if ( alpha*s[3] == 0 ) { + /* NOP */ + } else { + unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]); + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255*255 * alpha*s[0], newa); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255*255 * alpha*s[1], newa); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255*255 * alpha*s[2], newa); + d[3] = DIV_ROUND(newa, 255*255); + } +} + +template<> static void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND(alpha*s[3]*s[0], 255*255); + d[1] = DIV_ROUND(alpha*s[3]*s[1], 255*255); + d[2] = DIV_ROUND(alpha*s[3]*s[2], 255*255); + d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255); +} + +template<> static void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND(alpha*s[0], 255); + d[1] = DIV_ROUND(alpha*s[1], 255); + d[2] = DIV_ROUND(alpha*s[2], 255); + d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255); +} + +template<> static void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255); + d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255); +} + +template<> static void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) { + d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255 * alpha*s[0], 255*255); + d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255 * alpha*s[1], 255*255); + d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255 * alpha*s[2], 255*255); + d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255); +} + + +// composeAlpha, iterates over all pixels and applies composePixel to each of them +template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> +static void composeAlpha(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + for(int y=0; y<h; y++) { + unsigned char* d = px; + const unsigned char* s = spx; + for(int x=0; x<w; x++) { + composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, alpha); + d += pixelSize[resultFormat]; + s += pixelSize[foregroundFormat]; + } + px += rs; + spx += srs; + } +} + +template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat> +static void composeMask(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + for(int y=0; y<h; y++) { + unsigned char* d = px; + const unsigned char* s = spx; + const unsigned char* m = mpx; + for(int x=0; x<w; x++) { + composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, *m); + d += pixelSize[resultFormat]; + s += pixelSize[foregroundFormat]; + m += 1; + } + px += rs; + spx += srs; + mpx += mrs; + } +} + +template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat> +static void composeColor(unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { + const unsigned char rgba_array[4] = {NR_RGBA32_R(rgba), NR_RGBA32_G(rgba), NR_RGBA32_B(rgba), NR_RGBA32_A(rgba)}; + for(int y=0; y<h; y++) { + unsigned char* d = px; + const unsigned char* m = mpx; + for(int x=0; x<w; x++) { + composePixel<resultFormat, backgroundFormat, R8G8B8A8N>(d, rgba_array, *m); + d += pixelSize[resultFormat]; + m += 1; + } + px += rs; + mpx += mrs; + } +} + +/* FINAL DST SRC */ + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); +} + + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); +} + +/* FINAL DST SRC MASK */ + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); +} + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); +} + +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); +} + +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); +} + + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { + composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs); +} + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { + composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs); +} + +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { + composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs); +} + +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) { + composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs); +} + +/* FINAL DST MASK COLOR */ + +void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { + composeColor<R8G8B8A8N, EMPTY>(px, w, h, rs, mpx, mrs, rgba); +} + +void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { + composeColor<R8G8B8A8P, EMPTY>(px, w, h, rs, mpx, mrs, rgba); +} + + +void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { + composeColor<R8G8B8, R8G8B8>(px, w, h, rs, spx, srs, rgba); +} + +void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { + composeColor<R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, rgba); +} + +void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) { + composeColor<R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, rgba); +} + +/* RGB */ + +void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) { + composeAlpha<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha); +} + +void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs); +} + +void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) { + composeMask<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs); +} diff --git a/src/libnr/nr-compose-reference.h b/src/libnr/nr-compose-reference.h new file mode 100644 index 000000000..8d004a135 --- /dev/null +++ b/src/libnr/nr-compose-reference.h @@ -0,0 +1,69 @@ +#ifndef __NR_COMPOSE_REFERENCE_H__ +#define __NR_COMPOSE_REFERENCE_H__ + +// Based on nr-pixblock.h +typedef enum { + A8 = 0, + R8G8B8, + R8G8B8A8N, + R8G8B8A8P, + EMPTY = -1 +} PIXEL_FORMAT; + +/* FINAL DST SRC */ + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); + +/* FINAL DST SRC MASK */ + +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, + const unsigned char *spx, int srs, + const unsigned char *mpx, int mrs); +void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, + const unsigned char *spx, int srs, + const unsigned char *mpx, int mrs); +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, + const unsigned char *spx, int srs, + const unsigned char *mpx, int mrs); +void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, + const unsigned char *spx, int srs, + const unsigned char *mpx, int mrs); + +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, + const unsigned char *s, int srs, + const unsigned char *m, int mrs); +void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, + const unsigned char *s, int srs, + const unsigned char *m, int mrs); +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, + const unsigned char *s, int srs, + const unsigned char *m, int mrs); +void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, + const unsigned char *s, int srs, + const unsigned char *m, int mrs); + +/* FINAL DST MASK COLOR */ + +void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); +void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba); + +void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); +void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); +void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba); + +/* RGB */ + +void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha); +void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); +void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs); + +#endif//__NR_COMPOSE_REFERENCE_H__ diff --git a/src/libnr/nr-compose-test.h b/src/libnr/nr-compose-test.h new file mode 100644 index 000000000..5b0d129c7 --- /dev/null +++ b/src/libnr/nr-compose-test.h @@ -0,0 +1,451 @@ + +#include <cxxtest/TestSuite.h> + +#include "nr-compose.h" +#include "nr-compose-reference.h" +#include <glib.h> +#include <memory.h> +#include <stdlib.h> + +static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; } +static inline unsigned char NR_PREMUL_111(unsigned int c, unsigned int a) { return static_cast<unsigned char>(DIV_ROUND(c*a, 255)); } + +template<PIXEL_FORMAT format> +static int IMGCMP(const unsigned char* a, const unsigned char* b, size_t n) { return memcmp(a, b, n); } + +template<> +static int IMGCMP<R8G8B8A8N>(const unsigned char* a, const unsigned char* b, size_t n) +{ + // If two pixels each have their alpha channel set to zero they're equivalent + // Note that this doesn't work for premultiplied values, as their color values should + // be zero when alpha is zero. + int cr = 0; + while(n && cr == 0) { + if ( a[3] != 0 || b[3] != 0 ) { + cr = memcmp(a, b, 4); + } + a+=4; + b+=4; + n-=4; + } + return cr; +} + +class NrComposeTest : public CxxTest::TestSuite { +private: + int const w, h; + + unsigned char* const dst_rgba_n_org; + unsigned char* const dst_rgba_p_org; + unsigned char* const dst_rgb_org; + + unsigned char* const dst1_rgba; + unsigned char* const dst2_rgba; + unsigned char* const src_rgba_n; + unsigned char* const src_rgba_p; + unsigned char* const dst1_rgb; + unsigned char* const dst2_rgb; + unsigned char* const src_rgb; + unsigned char* const mask; + + static unsigned int const alpha_vals[7]; + static unsigned int const rgb_vals[3]; + +public: + NrComposeTest() : + w(13), + h(5), + + dst_rgba_n_org(new unsigned char[w*h*4]), + dst_rgba_p_org(new unsigned char[w*h*4]), + dst_rgb_org(new unsigned char[w*h*3]), + + dst1_rgba(new unsigned char[w*h*4]), + dst2_rgba(new unsigned char[w*h*4]), + src_rgba_n(new unsigned char[w*h*4]), + src_rgba_p(new unsigned char[w*h*4]), + dst1_rgb(new unsigned char[w*h*3]), + dst2_rgb(new unsigned char[w*h*3]), + src_rgb(new unsigned char[w*h*3]), + mask(new unsigned char[w*h]) + { + srand(23874683); // It shouldn't really matter what this is, as long as it's always the same (to be reproducible) + + for(int y=0; y<h; y++) { + for(int x=0; x<w; x++) { + dst_rgba_n_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX; + dst_rgba_p_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX; + src_rgba_n[(x+y*w)*4+3] = 255*rand()/RAND_MAX; + src_rgba_p[(x+y*w)*4+3] = 255*rand()/RAND_MAX; + for(int i=0; i<3; i++) { + dst_rgba_n_org[(x+y*w)*4+i] = 255*rand()/RAND_MAX; + dst_rgba_p_org[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, dst_rgba_p_org[(x+y*w)*4+3]); + src_rgba_n[(x+y*w)*4+i] = 255*rand()/RAND_MAX; + src_rgba_p[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, src_rgba_p[(x+y*w)*4+3]); + dst_rgb_org[(x+y*w)*3+i] = 255*rand()/RAND_MAX; + } + mask[x+y*w] = 255*rand()/RAND_MAX; + } + } + } + virtual ~NrComposeTest() + { + delete[] dst_rgba_n_org; + delete[] dst_rgba_p_org; + delete[] dst_rgb_org; + + delete[] dst1_rgba; + delete[] dst2_rgba; + delete[] src_rgba_n; + delete[] src_rgba_p; + delete[] dst1_rgb; + delete[] dst2_rgb; + delete[] src_rgb; + delete[] mask; + } + + // FINAL DST SRC + + void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + + // FINAL DST SRC MASK + + void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8() + { + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8() + { + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8() + { + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8() + { + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8() + { + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8() + { + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8() + { + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8() + { + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w); + TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + + // FINAL DST MASK COLOR + + void testnr_R8G8B8A8_N_EMPTY_A8_RGBA32() + { + for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int rgba = rgb_vals[j]+alpha_vals[i]; + char msg[100]; + sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); + nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + } + + void testnr_R8G8B8A8_P_EMPTY_A8_RGBA32() + { + for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int rgba = rgb_vals[j]+alpha_vals[i]; + char msg[100]; + sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); + nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + } + + void testnr_R8G8B8_R8G8B8_A8_RGBA32() + { + for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int rgba = rgb_vals[j]+alpha_vals[i]; + char msg[100]; + sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); + memcpy(dst1_rgb, dst_rgb_org, w*h*3); + memcpy(dst2_rgb, dst_rgb_org, w*h*3); + nr_R8G8B8_R8G8B8_A8_RGBA32(dst1_rgb, w, h, w*3, mask, w, rgba); + nr_R8G8B8_R8G8B8_A8_RGBA32_ref(dst2_rgb, w, h, w*3, mask, w, rgba); + TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); + } + } + } + + void testnr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32() + { + for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int rgba = rgb_vals[j]+alpha_vals[i]; + char msg[100]; + sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); + memcpy(dst1_rgba, dst_rgba_n_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_n_org, w*h*4); + nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); + nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + } + + void testnr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32() + { + for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int rgba = rgb_vals[j]+alpha_vals[i]; + char msg[100]; + sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff); + memcpy(dst1_rgba, dst_rgba_p_org, w*h*4); + memcpy(dst2_rgba, dst_rgba_p_org, w*h*4); + nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba); + nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba); + TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 ); + } + } + } + + // RGB + + void testnr_R8G8B8_R8G8B8_R8G8B8A8_N() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgb, dst_rgb_org, w*h*3); + memcpy(dst2_rgb, dst_rgb_org, w*h*3); + nr_R8G8B8_R8G8B8_R8G8B8A8_N(dst1_rgb, w, h, w*3, src_rgba_n, w*4, alpha); + nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); + } + } + + void testnr_R8G8B8_R8G8B8_R8G8B8A8_P() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgb, dst_rgb_org, w*h*3); + memcpy(dst2_rgb, dst_rgb_org, w*h*3); + nr_R8G8B8_R8G8B8_R8G8B8A8_P(dst1_rgb, w, h, w*3, src_rgba_p, w*4, alpha); + nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, alpha); + TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); + } + } + + void testnr_R8G8B8_R8G8B8_R8G8B8A8_N_A8() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgb, dst_rgb_org, w*h*3); + memcpy(dst2_rgb, dst_rgb_org, w*h*3); + nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8(dst1_rgb, w, h, w*3, src_rgba_n, w*4, mask, w); + nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, mask, w); + TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); + } + } + + void testnr_R8G8B8_R8G8B8_R8G8B8A8_P_A8() + { + for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) { + unsigned int alpha = alpha_vals[i]; + char msg[40]; + sprintf(msg, "alpha = %u", alpha); + memcpy(dst1_rgb, dst_rgb_org, w*h*3); + memcpy(dst2_rgb, dst_rgb_org, w*h*3); + nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8(dst1_rgb, w, h, w*3, src_rgba_p, w*4, mask, w); + nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, mask, w); + TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 ); + } + } +}; + +unsigned int const NrComposeTest::alpha_vals[7] = {0, 1, 127, 128, 129, 254, 255}; +unsigned int const NrComposeTest::rgb_vals[3] = { + ( 0u<<24u)+( 1u<<16u)+( 92u<<8u), + (127u<<24u)+(128u<<16u)+(129u<<8u), + (163u<<24u)+(254u<<16u)+(255u<<8u)}; + +/* +Local Variables: +mode:c++ +c-file-style:"stroustrup" +c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) +indent-tabs-mode:nil +fill-column:99 +End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/svg/svg-affine-test.h b/src/svg/svg-affine-test.h index 658968bce..0284402ed 100644 --- a/src/svg/svg-affine-test.h +++ b/src/svg/svg-affine-test.h @@ -40,6 +40,7 @@ private: static test_t const read_scale_tests[3]; static test_t const read_rotate_tests[4]; static test_t const read_skew_tests[3]; + static char const * read_fail_tests[25]; static test_t const write_matrix_tests[2]; static test_t const write_translate_tests[3]; static test_t const write_scale_tests[2]; @@ -155,6 +156,9 @@ public: void testReadConcatenation() { + // NOTE: According to the SVG specification (see the syntax at http://www.w3.org/TR/SVG/coords.html#TransformAttribute + // there should be 1 or more comma-wsp sequences between transforms... This doesn't make sense and it seems + // likely that instead of a + they meant a ? (zero or one comma-wsp sequences). char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)"; Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica Geom::Matrix cm; @@ -162,15 +166,21 @@ public: TS_ASSERT_RELATION(approx_equal , ref , cm); } - // TODO: Perhaps check faulty transforms (like "translate(1,2,3)", or "matrix(1,2,3,4,5)", or ...) + void testReadFailures() + { + for(size_t i=0; i<G_N_ELEMENTS(read_fail_tests); i++) { + Geom::Matrix cm; + TSM_ASSERT(read_fail_tests[i] , !sp_svg_transform_read(read_fail_tests[i], &cm)); + } + } }; static double const DEGREE = M_PI/180.; SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = { {"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)}, - {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, - {"matrix(1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}}; + {" matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, + {"matrix (1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}}; SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = { {"translate(1)",Geom::Matrix(1,0,0,1,1,0)}, {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)}, @@ -188,6 +198,32 @@ SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = { {"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)}, {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)}, {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}}; +char const * SvgAffineTest::read_fail_tests[25] = { + "matrix((1,2,3,4,5,6)", + "matrix((1,2,3,4,5,6))", + "matrix(1,2,3,4,5,6))", + "matrix(,1,2,3,4,5,6)", + "matrix(1,2,3,4,5,6,)", + "matrix(1,2,3,4,5,)", + "matrix(1,2,3,4,5)", + "matrix(1,2,3,4,5e6-3)", // Here numbers HAVE to be separated by a comma-wsp sequence + "matrix(1,2,3,4,5e6.3)", // Here numbers HAVE to be separated by a comma-wsp sequence + "translate()", + "translate(,)", + "translate(1,)", + "translate(1,6,)", + "translate(1,6,0)", + "scale()", + "scale(1,6,2)", + "rotate()", + "rotate(1,6)", + "rotate(1,6,)", + "rotate(1,6,3,4)", + "skewX()", + "skewX(-)", + "skewX(.)", + "skewY(,)", + "skewY(1,2)"}; SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = { {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, diff --git a/src/svg/svg-length-test.h b/src/svg/svg-length-test.h index f6c6cb4f6..2345803d8 100644 --- a/src/svg/svg-length-test.h +++ b/src/svg/svg-length-test.h @@ -7,33 +7,114 @@ class SvgLengthTest : public CxxTest::TestSuite { private: + struct test_t { + char const* str; SVGLength::Unit unit; float value; float computed; + }; + static test_t const absolute_tests[12]; + static test_t const relative_tests[3]; + static char const * fail_tests[8]; public: SvgLengthTest() { } void testRead() { - struct test_t { - char const* str; float computed; - test_t(char const* str, float computed) : str(str), computed(computed) {} - }; - test_t tests[] = { - test_t("0",0), - test_t("1",1), - test_t("1.00001",1.00001), - test_t("1px",1), - test_t(".1px",0.1)}; - size_t n = G_N_ELEMENTS(tests); - for(size_t i=0; i<n; i++) { - SVGLength l; - TSM_ASSERT(tests[i].str , l.read(tests[i].str)); - TSM_ASSERT_EQUALS(tests[i].str , l.computed , tests[i].computed); + for(size_t i=0; i<G_N_ELEMENTS(absolute_tests); i++) { + SVGLength l; + TSM_ASSERT(absolute_tests[i].str , l.read(absolute_tests[i].str)); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.unit , absolute_tests[i].unit); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.value , absolute_tests[i].value); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.computed , absolute_tests[i].computed); + } + for(size_t i=0; i<G_N_ELEMENTS(relative_tests); i++) { + SVGLength l; + TSM_ASSERT(relative_tests[i].str , l.read(relative_tests[i].str)); + l.update(7,13,19); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.unit , relative_tests[i].unit); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.value , relative_tests[i].value); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.computed , relative_tests[i].computed); + } + for(size_t i=0; i<G_N_ELEMENTS(fail_tests); i++) { + SVGLength l; + TSM_ASSERT(fail_tests[i] , !l.read(fail_tests[i])); + } + } + + void testReadOrUnset() + { + for(size_t i=0; i<G_N_ELEMENTS(absolute_tests); i++) { + SVGLength l; + l.readOrUnset(absolute_tests[i].str); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.unit , absolute_tests[i].unit); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.value , absolute_tests[i].value); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.computed , absolute_tests[i].computed); + } + for(size_t i=0; i<G_N_ELEMENTS(relative_tests); i++) { + SVGLength l; + l.readOrUnset(relative_tests[i].str); + l.update(7,13,19); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.unit , relative_tests[i].unit); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.value , relative_tests[i].value); + TSM_ASSERT_EQUALS(relative_tests[i].str , l.computed , relative_tests[i].computed); + } + for(size_t i=0; i<G_N_ELEMENTS(fail_tests); i++) { + SVGLength l; + l.readOrUnset(fail_tests[i], SVGLength::INCH, 123, 456); + TSM_ASSERT_EQUALS(fail_tests[i] , l.unit , SVGLength::INCH); + TSM_ASSERT_EQUALS(fail_tests[i] , l.value , 123); + TSM_ASSERT_EQUALS(fail_tests[i] , l.computed , 456); + } + } + + void testReadAbsolute() + { + for(size_t i=0; i<G_N_ELEMENTS(absolute_tests); i++) { + SVGLength l; + TSM_ASSERT(absolute_tests[i].str , l.readAbsolute(absolute_tests[i].str)); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.unit , absolute_tests[i].unit); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.value , absolute_tests[i].value); + TSM_ASSERT_EQUALS(absolute_tests[i].str , l.computed , absolute_tests[i].computed); + } + for(size_t i=0; i<G_N_ELEMENTS(relative_tests); i++) { + SVGLength l; + TSM_ASSERT(relative_tests[i].str , !l.readAbsolute(relative_tests[i].str)); + } + for(size_t i=0; i<G_N_ELEMENTS(fail_tests); i++) { + SVGLength l; + TSM_ASSERT(fail_tests[i] , !l.readAbsolute(fail_tests[i])); } } // TODO: More tests }; +SvgLengthTest::test_t const SvgLengthTest::absolute_tests[12] = { + {"0", SVGLength::NONE, 0 , 0}, + {"1", SVGLength::NONE, 1 , 1}, + {"1.00001", SVGLength::NONE, 1.00001 , 1.00001}, + {"1px", SVGLength::PX , 1 , 1}, + {".1px", SVGLength::PX , 0.1 , 0.1}, + {"100pt", SVGLength::PT , 100 , 125}, + {"1e2pt", SVGLength::PT , 100 , 125}, + {"3pc", SVGLength::PC , 3 , 45}, + {"-3.5pc", SVGLength::PC , -3.5 , -3.5*15.}, + {"1.2345678mm", SVGLength::MM , 1.2345678, 1.2345678*3.543307}, // TODO: More precise constants? (a 7 digit constant when the default precision is 8 digits?) + {"123.45678cm", SVGLength::CM , 123.45678 , 123.45678*35.43307}, + {"73.162987in", SVGLength::INCH, 73.162987 , 73.162987*90}}; +SvgLengthTest::test_t const SvgLengthTest::relative_tests[3] = { + {"123em", SVGLength::EM, 123, 123. * 7.}, + {"123ex", SVGLength::EX, 123, 123. * 13.}, + {"123%", SVGLength::PERCENT, 1.23, 1.23 * 19.}}; +char const * SvgLengthTest::fail_tests[8] = { + "123 px", + "123e", + "123e+m", + "123ec", + "123pxt", + "--123", + "", + "px"}; + /* Local Variables: mode:c++ |
