summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d5b7e1b)
raw | patch | inline | side by side (parent: d5b7e1b)
author | jaspervdg <jaspervdg@users.sourceforge.net> | |
Sat, 5 Jul 2008 14:56:14 +0000 (14:56 +0000) | ||
committer | jaspervdg <jaspervdg@users.sourceforge.net> | |
Sat, 5 Jul 2008 14:56:14 +0000 (14:56 +0000) |
build.xml | patch | blob | history | |
src/libnr/nr-compose-reference.cpp | [new file with mode: 0644] | patch | blob |
src/libnr/nr-compose-reference.h | [new file with mode: 0644] | patch | blob |
src/libnr/nr-compose-test.h | [new file with mode: 0644] | patch | blob |
src/svg/svg-affine-test.h | patch | blob | history | |
src/svg/svg-length-test.h | patch | blob | history |
diff --git a/build.xml b/build.xml
index 2ab7104e24a6e9a46397b262e13e303f0ff12203..ac34d71f475c8a7a918f0d96375da28c5541b491 100644 (file)
--- a/build.xml
+++ b/build.xml
<cxxtestpart command="python ${cxxtest}/cxxtestgen.py"
out="${src}/libnr/test-nr.cpp">
<fileset dir="${src}/libnr">
+ <include name="nr-compose-test.h"/>
<include name="nr-types-test.h"/>
<include name="nr-translate-test.h"/>
<include name="nr-rotate-test.h"/>
<exclude name="libnr/test-nr-main.cpp"/>
<exclude name="libnr/testnr.cpp"/>
<exclude name="libnr/in-svg-plane-test.cpp"/>
- <exclude name="libnr/nr-compose-reference.cpp"/>
- <exclude name="libnr/nr-compose-test.cpp"/>
<exclude name="libnr/nr-matrix-test.cpp"/>
<exclude name="libnr/nr-point-fns-test.cpp"/>
<exclude name="libnr/nr-rotate-fns-test.cpp"/>
<exclude name="obj/test-src.o"/>
<exclude name="obj/display/test-display.o"/>
<exclude name="obj/helper/test-helper.o"/>
+ <exclude name="obj/libnr/nr-compose-reference.o"/>
<exclude name="obj/libnr/test-nr.o"/>
<exclude name="obj/svg/test-svg.o"/>
<exclude name="obj/util/test-util.o"/>
<include name="obj/test-src.o"/>
<include name="obj/display/test-display.o"/>
<include name="obj/helper/test-helper.o"/>
+ <include name="obj/libnr/nr-compose-reference.o"/>
<include name="obj/libnr/test-nr.o"/>
<include name="obj/svg/test-svg.o"/>
<include name="obj/util/test-util.o"/>
diff --git a/src/libnr/nr-compose-reference.cpp b/src/libnr/nr-compose-reference.cpp
--- /dev/null
@@ -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
--- /dev/null
@@ -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
--- /dev/null
@@ -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 :
index 658968bce88b916d17b8f68fb95a51a0c8a18a6f..0284402edcd6dba0c5a7ac0b5785468a920b6995 100644 (file)
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];
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;
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)},
{"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)},
index f6c6cb4f696b9ab4938bfc83fa0f7a13b9f54e87..2345803d86a68d8915a50d91a8deade81e9f557b 100644 (file)
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++