[sodipodi] [merge from sf] Added some blitting methods and image scaling/masking



commit cd50bfbdb4032c10c626a863be25f2e55b83370c
Author: Hans Breuer <hans breuer org>
Date:   Fri Oct 5 19:50:00 2012 +0200

    [merge from sf] Added some blitting methods and image scaling/masking
    
    From: lauris <lauris 2490c5c0-b34c-4913-a0bd-69599dd9f015>
    Date: Thu, 13 Oct 2011 23:23:32 +0000
    git-svn-id: https://sodipodi.svn.sourceforge.net/svnroot/sodipodi/trunk 719 2490c5c0-b34c-4913-a0bd-69599dd9f015
    
    From: lauris <lauris 2490c5c0-b34c-4913-a0bd-69599dd9f015>
    Date: Fri, 23 Mar 2012 00:18:30 +0000
    Subject: [PATCH 127/129] Added some G8 blitters
    
    git-svn-id: https://sodipodi.svn.sourceforge.net/svnroot/sodipodi/trunk 728 2490c5c0-b34c-4913-a0bd-69599dd9f015
    
    Plus preconditions;)

 src/display/nr-arena-glyphs.c   |    4 +-
 src/display/nr-arena-item.c     |    2 +-
 src/display/nr-arena-shape.c    |    4 +-
 src/helper/nr-gradient-gpl.c    |    6 +-
 src/libnr/nr-blit.c             |   97 +++++++++-----
 src/libnr/nr-blit.h             |    6 +-
 src/libnr/nr-compose.c          |  287 ++++++++++++++++++++++++++++++++++++++-
 src/libnr/nr-compose.h          |   28 +++--
 src/libnr/nr-gradient.c         |    4 +-
 src/libnr/nr-pixblock-pattern.c |    4 +-
 src/libnr/nr-pixblock-pixel.c   |   20 ++--
 src/libnr/nr-pixblock.c         |  208 +++++++++++++++++++++++++---
 src/libnr/nr-pixblock.h         |   28 ++++-
 src/libnr/nr-types.h            |    2 +
 src/libnr/testnr.c              |    2 +-
 src/libnrtype/nr-rasterfont.c   |    4 +-
 src/widgets/font-selector.c     |    2 +-
 17 files changed, 608 insertions(+), 100 deletions(-)
---
diff --git a/src/display/nr-arena-glyphs.c b/src/display/nr-arena-glyphs.c
index 5c84f13..603c4e5 100644
--- a/src/display/nr-arena-glyphs.c
+++ b/src/display/nr-arena-glyphs.c
@@ -452,7 +452,7 @@ nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb,
 	if (style->fill.type != SP_PAINT_TYPE_NONE) {
 		NRPixBlock mb;
 		guint32 rgba;
-		nr_pixblock_setup_fast (&mb, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
+		nr_pixblock_setup_fast (&mb, NR_PIXBLOCK_MODE_G8, area->x0, area->y0, area->x1, area->y1, TRUE);
 		/* Render children fill mask */
 		for (child = group->children; child != NULL; child = child->next) {
 			ret = nr_arena_glyphs_fill_mask (NR_ARENA_GLYPHS (child), area, &mb);
@@ -493,7 +493,7 @@ nr_arena_glyphs_group_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb,
 	if (style->stroke.type != SP_PAINT_TYPE_NONE) {
 		NRPixBlock m;
 		guint32 rgba;
-		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
+		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_G8, area->x0, area->y0, area->x1, area->y1, TRUE);
 		/* Render children stroke mask */
 		for (child = group->children; child != NULL; child = child->next) {
 			ret = nr_arena_glyphs_stroke_mask (NR_ARENA_GLYPHS (child), area, &m);
diff --git a/src/display/nr-arena-item.c b/src/display/nr-arena-item.c
index 0a154fe..6e36d84 100644
--- a/src/display/nr-arena-item.c
+++ b/src/display/nr-arena-item.c
@@ -329,7 +329,7 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, u
 
 		if (item->clip || item->mask) {
 			/* Setup mask pixblock */
-			nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
+			nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_G8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
 			/* Do clip if needed */
 			if (item->clip) {
 				state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
diff --git a/src/display/nr-arena-shape.c b/src/display/nr-arena-shape.c
index 69b6a68..54fa79d 100644
--- a/src/display/nr-arena-shape.c
+++ b/src/display/nr-arena-shape.c
@@ -452,7 +452,7 @@ nr_arena_shape_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigne
 		NRPixBlock m;
 		guint32 rgba;
 
-		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
+		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_G8, area->x0, area->y0, area->x1, area->y1, TRUE);
 		nr_pixblock_render_svp_mask_or (&m, shape->fill_svp);
 		m.empty = FALSE;
 
@@ -489,7 +489,7 @@ nr_arena_shape_render (NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigne
 		NRPixBlock m;
 		guint32 rgba;
 
-		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, area->x0, area->y0, area->x1, area->y1, TRUE);
+		nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_G8, area->x0, area->y0, area->x1, area->y1, TRUE);
 		nr_pixblock_render_svp_mask_or (&m, shape->stroke_svp);
 		m.empty = FALSE;
 
diff --git a/src/helper/nr-gradient-gpl.c b/src/helper/nr-gradient-gpl.c
index c480996..e03bee0 100644
--- a/src/helper/nr-gradient-gpl.c
+++ b/src/helper/nr-gradient-gpl.c
@@ -84,7 +84,7 @@ nr_lgradient_render_block (NRRenderer *r, NRPixBlock *pb, NRPixBlock *m)
 #else
 	if (pb->empty) {
 		switch (pb->mode) {
-		case NR_PIXBLOCK_MODE_A8:
+		case NR_PIXBLOCK_MODE_G8:
 			nr_lgradient_render_generic (lgr, pb);
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8:
@@ -101,7 +101,7 @@ nr_lgradient_render_block (NRRenderer *r, NRPixBlock *pb, NRPixBlock *m)
 		}
 	} else {
 		switch (pb->mode) {
-		case NR_PIXBLOCK_MODE_A8:
+		case NR_PIXBLOCK_MODE_G8:
 			nr_lgradient_render_generic (lgr, pb);
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8:
@@ -283,7 +283,7 @@ nr_lgradient_render_generic (NRLGradientRenderer *lgr, NRPixBlock *pb)
 				  (unsigned char *) lgr->vector,
 				  4 * NR_GRADIENT_VECTOR_LENGTH,
 				  0, 0);
-	bpp = (pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+	bpp = (pb->mode == NR_PIXBLOCK_MODE_G8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
 	for (y = 0; y < height; y++) {
 		d = NR_PIXBLOCK_PX (pb) + y * rs;
diff --git a/src/libnr/nr-blit.c b/src/libnr/nr-blit.c
index ac605ac..60d027c 100644
--- a/src/libnr/nr-blit.c
+++ b/src/libnr/nr-blit.c
@@ -12,22 +12,21 @@
 #include "nr-rect.h"
 #include "nr-pixops.h"
 #include "nr-compose.h"
+#include "nr-pixblock.h"
+
 #include "nr-blit.h"
 
 void
-nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alpha)
+nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, const NRPixBlock *s, unsigned int alpha)
 {
 	NRRectS clip;
-	unsigned char *dpx, *spx;
+	unsigned char *dpx;
+	const unsigned char *spx;
 	int dbpp, sbpp;
 	int w, h;
 
 	if (alpha == 0) return;
 	if (s->empty) return;
-	/* fixme: */
-	if (s->mode == NR_PIXBLOCK_MODE_A8) return;
-	/* fixme: */
-	if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) return;
 
 	/*
 	 * Possible variants as of now:
@@ -64,14 +63,34 @@ nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alph
 	h = clip.y1 - clip.y0;
 
 	switch (d->mode) {
-	case NR_PIXBLOCK_MODE_A8:
-		/* No rendering into alpha at moment */
+	case NR_PIXBLOCK_MODE_G8:
+		if (d->empty) {
+			if (s->mode == NR_PIXBLOCK_MODE_G8) {
+				nr_A8_EMPTY_A8 (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+				nr_A8_EMPTY_R8G8B8 (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
+				nr_A8_EMPTY_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
+				nr_A8_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
+			}
+		} else {
+			/* fixme: Implement (Lauris) */
+		}
 		break;
 	case NR_PIXBLOCK_MODE_R8G8B8:
-		if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
-			nr_R8G8B8_R8G8B8_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
+		if (d->empty) {
+			/* fixme: Implement (Lauris) */
 		} else {
-			nr_R8G8B8_R8G8B8_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			if (s->mode == NR_PIXBLOCK_MODE_G8) {
+				/* fixme: Implement mask rendering (Lauris) */
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+				nr_R8G8B8_R8G8B8_R8G8B8 (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
+				nr_R8G8B8_R8G8B8_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else {
+				nr_R8G8B8_R8G8B8_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
+			}
 		}
 		break;
 	case NR_PIXBLOCK_MODE_R8G8B8A8P:
@@ -79,36 +98,46 @@ nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alph
 			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
 				/* Case 8 */
 				nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
-			} else {
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
 				/* Case C */
 				nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else {
+				/* fixme: Implement mask and RGB rendering (Lauris) */
 			}
 		} else {
 			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
 				/* case A */
 				nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
-			} else {
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
 				/* case E */
 				nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else {
+				/* fixme: Implement mask and RGB rendering (Lauris) */
 			}
 		}
 		break;
 	case NR_PIXBLOCK_MODE_R8G8B8A8N:
 		if (d->empty) {
-			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
-				/* Case 9 */
-				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
-			} else {
-				/* Case D */
+			if (s->mode == NR_PIXBLOCK_MODE_G8) {
+				/* fixme: Implement (Lauris) */
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+				nr_R8G8B8A8_N_EMPTY_R8G8B8 (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
 				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else {
+				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
 			}
 		} else {
 			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
 				/* case B */
 				nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P (dpx, w, h, d->rs, spx, s->rs, alpha);
-			} else {
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
 				/* case F */
 				nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else  if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+				nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8 (dpx, w, h, d->rs, spx, s->rs, alpha);
+			} else {
+				/* fixme: Implement mask rendering (Lauris) */
 			}
 		}
 		break;
@@ -116,18 +145,15 @@ nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alph
 }
 
 void
-nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m)
+nr_blit_pixblock_pixblock_mask (NRPixBlock *d, const NRPixBlock *s, const NRPixBlock *m)
 {
 	NRRectS clip;
-	unsigned char *dpx, *spx, *mpx;
+	unsigned char *dpx;
+	const unsigned char *spx, *mpx;
 	int dbpp, sbpp;
 	int w, h;
 
 	if (s->empty) return;
-	/* fixme: */
-	if (s->mode == NR_PIXBLOCK_MODE_A8) return;
-	/* fixme: */
-	if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) return;
 
 	/*
 	 * Possible variants as of now:
@@ -166,7 +192,7 @@ nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m)
 	h = clip.y1 - clip.y0;
 
 	switch (d->mode) {
-	case NR_PIXBLOCK_MODE_A8:
+	case NR_PIXBLOCK_MODE_G8:
 		/* No rendering into alpha at moment */
 		break;
 	case NR_PIXBLOCK_MODE_R8G8B8:
@@ -197,12 +223,14 @@ nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m)
 		break;
 	case NR_PIXBLOCK_MODE_R8G8B8A8N:
 		if (d->empty) {
-			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
-				/* Case 9 */
-				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs);
-			} else {
-				/* Case D */
+			if (s->mode == NR_PIXBLOCK_MODE_G8) {
+				nr_R8G8B8A8_N_EMPTY_A8_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8) {
+				nr_R8G8B8A8_N_EMPTY_R8G8B8_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs);
+			} else if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
 				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs);
+			} else {
+				nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (dpx, w, h, d->rs, spx, s->rs, mpx, m->rs);
 			}
 		} else {
 			if (s->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
@@ -218,16 +246,17 @@ nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m)
 }
 
 void
-nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, NRPixBlock *m, unsigned long rgba)
+nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, const NRPixBlock *m, unsigned long rgba)
 {
 	if (!(rgba & 0xff)) return;
 
 	if (m) {
 		NRRectS clip;
-		unsigned char *dpx, *mpx;
+		unsigned char *dpx;
+		const unsigned char *mpx;
 		int w, h;
 
-		if (m->mode != NR_PIXBLOCK_MODE_A8) return;
+		if (m->mode != NR_PIXBLOCK_MODE_G8) return;
 
 		if (!nr_rect_s_test_intersect (&d->area, &m->area)) return;
 
diff --git a/src/libnr/nr-blit.h b/src/libnr/nr-blit.h
index 9bc5780..d2f2b72 100644
--- a/src/libnr/nr-blit.h
+++ b/src/libnr/nr-blit.h
@@ -18,9 +18,9 @@ extern "C" {
 
 #define nr_blit_pixblock_pixblock(d,s) nr_blit_pixblock_pixblock_alpha (d, s, 255)
 
-void nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, NRPixBlock *s, unsigned int alpha);
-void nr_blit_pixblock_pixblock_mask (NRPixBlock *d, NRPixBlock *s, NRPixBlock *m);
-void nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, NRPixBlock *m, unsigned long rgba32);
+void nr_blit_pixblock_pixblock_alpha (NRPixBlock *d, const NRPixBlock *s, unsigned int alpha);
+void nr_blit_pixblock_pixblock_mask (NRPixBlock *d, const NRPixBlock *s, const NRPixBlock *m);
+void nr_blit_pixblock_mask_rgba32 (NRPixBlock *d, const NRPixBlock *m, unsigned long rgba32);
 
 #ifdef __cplusplus
 };
diff --git a/src/libnr/nr-compose.c b/src/libnr/nr-compose.c
index 0d6ed4c..428bba6 100644
--- a/src/libnr/nr-compose.c
+++ b/src/libnr/nr-compose.c
@@ -27,6 +27,175 @@ void nr_mmx_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, c
 #endif
 
 void
+nr_A8_EMPTY_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+	if (alpha == 0) {
+		/* Clear destination */
+		for (r = 0; r < h; r++) {
+			memset (px, 0x0, w);
+			px += rs;
+		}
+	} else if (alpha == 255) {
+		/* Copy source */
+		for (r = 0; r < h; r++) {
+			memcpy (px, spx, w);
+			px += rs;
+			spx += srs;
+		}
+	} else {
+		/* Copy multiplied */
+		const unsigned char *s;
+		unsigned char *d;
+		d = px;
+		s = spx;
+		for (c = 0; c < w; c++) {
+			d[0] = (s[0] * alpha + 127) / 255;
+			d += 1;
+			s += 1;
+		}
+		px += rs;
+		spx += srs;
+	}
+}
+
+void
+nr_A8_EMPTY_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+	if (alpha == 0) {
+		/* Clear destination */
+		for (r = 0; r < h; r++) {
+			memset (px, 0x0, w);
+			px += rs;
+		}
+	} else if (alpha == 255) {
+		/* Copy average */
+		for (r = 0; r < h; r++) {
+			const unsigned char *s;
+			unsigned char *d;
+			d = px;
+			s = spx;
+			for (c = 0; c < w; c++) {
+				d[0] = (s[0] + s[1] + s[2] + 1) / 3;
+				d += 1;
+				s += 3;
+			}
+			px += rs;
+			spx += srs;
+		}
+	} else {
+		/* Copy average multiplied */
+		for (r = 0; r < h; r++) {
+			const unsigned char *s;
+			unsigned char *d;
+			d = px;
+			s = spx;
+			for (c = 0; c < w; c++) {
+				d[0] = ((s[0] + s[1] + s[2]) * alpha + 383) / 767;
+				d += 1;
+				s += 3;
+			}
+			px += rs;
+			spx += srs;
+		}
+	}
+}
+
+/* fixme: This composition is not 100% correct */
+
+void
+nr_A8_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+	if (alpha == 0) {
+		/* Clear destination */
+		for (r = 0; r < h; r++) {
+			memset (px, 0x0, w);
+			px += rs;
+		}
+	} else {
+		/* Copy average multiplied */
+		for (r = 0; r < h; r++) {
+			const unsigned char *s;
+			unsigned char *d;
+			d = px;
+			s = spx;
+			for (c = 0; c < w; c++) {
+				d[0] = ((s[0] + s[1] + s[2]) * alpha + 383) / 767;
+				d += 1;
+				s += 4;
+			}
+			px += rs;
+			spx += srs;
+		}
+	}
+}
+
+/* fixme: This composition is not 100% correct */
+
+void
+nr_A8_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+	if (alpha == 0) {
+		/* Clear destination */
+		for (r = 0; r < h; r++) {
+			memset (px, 0x0, w);
+			px += rs;
+		}
+	} else {
+		/* Copy average multiplied */
+		for (r = 0; r < h; r++) {
+			const unsigned char *s;
+			unsigned char *d;
+			d = px;
+			s = spx;
+			for (c = 0; c < w; c++) {
+				unsigned int a;
+				a = NR_PREMUL (s[3], alpha);
+				if (a == 0) {
+					d[0] = ((s[0] + s[1] + s[2]) * alpha + 383) / 767;
+				} else if (a == 255) {
+					d[0] = (s[0] + s[1] + s[2] + 1) / 3;
+				} else {
+					d[0] = ((s[0] + s[1] + s[2]) * 255 + a) / (3 * a);
+				}
+				d += 1;
+				s += 4;
+			}
+			px += rs;
+			spx += srs;
+		}
+	}
+}
+
+void
+nr_R8G8B8A8_N_EMPTY_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+
+	for (r = 0; r < h; r++) {
+		if (alpha == 0) {
+			memset (px, 0x0, 4 * w);
+		} else {
+			const unsigned char *s;
+			unsigned char *d;
+			d = px;
+			s = spx;
+			for (c = 0; c < w; c++) {
+				*d++ = *s++;
+				*d++ = *s++;
+				*d++ = *s++;
+				*d++ = alpha;
+			}
+		}
+		px += rs;
+		spx += srs;
+	}
+}
+
+void
 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
 {
 	int r, c;
@@ -52,7 +221,6 @@ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const u
 		spx += srs;
 	}
 }
-
 void
 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
 {
@@ -147,6 +315,44 @@ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const u
 	}
 }
 
+/* fixme: This is not optimized (Lauris) */
+void
+nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+
+	if (alpha == 0) return;
+
+	for (r = 0; r < h; r++) {
+		unsigned char *d, *s;
+		d = (unsigned char *) px;
+		s = (unsigned char *) spx;
+		for (c = 0; c < w; c++) {
+			unsigned int a;
+			a = alpha;
+			if ((a == 255) || (d[3] == 0)) {
+				/* Full coverage, COPY */
+				d[0] = s[0];
+				d[1] = s[1];
+				d[2] = s[2];
+				d[3] = a;
+			} else {
+				unsigned int ca;
+				/* Full composition */
+				ca = 65025 - (255 - a) * (255 - d[3]);
+				d[0] = NR_COMPOSENNN_A7 (s[0], a, d[0], d[3], ca);
+				d[1] = NR_COMPOSENNN_A7 (s[1], a, d[1], d[3], ca);
+				d[2] = NR_COMPOSENNN_A7 (s[2], a, d[2], d[3], ca);
+				d[3] = (ca + 127) / 255;
+			}
+			d += 4;
+			s += 3;
+		}
+		px += rs;
+		spx += srs;
+	}
+}
+
 void
 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
 {
@@ -317,10 +523,57 @@ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, co
 /* Masked operations */
 
 void
-nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
+nr_R8G8B8A8_N_EMPTY_A8_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
 {
 	int x, y;
+	for (y = 0; y < h; y++) {
+		unsigned char *d, *s, *m;
+		d = (unsigned char *) px;
+		s = (unsigned char *) spx;
+		m = (unsigned char *) mpx;
+		for (x = 0; x < w; x++) {
+			d[0] = s[0];
+			d[1] = s[0];
+			d[2] = s[0];
+			d[3] = m[0];
+			d += 4;
+			s += 1;
+			m += 1;
+		}
+		px += rs;
+		spx += srs;
+		mpx += mrs;
+	}
+}
+
+void
+nr_R8G8B8A8_N_EMPTY_R8G8B8_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
+{
+	int x, y;
+	for (y = 0; y < h; y++) {
+		unsigned char *d, *s, *m;
+		d = (unsigned char *) px;
+		s = (unsigned char *) spx;
+		m = (unsigned char *) mpx;
+		for (x = 0; x < w; x++) {
+			d[0] = s[0];
+			d[1] = s[1];
+			d[2] = s[2];
+			d[3] = m[0];
+			d += 4;
+			s += 3;
+			m += 1;
+		}
+		px += rs;
+		spx += srs;
+		mpx += mrs;
+	}
+}
 
+void
+nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
+{
+	int x, y;
 	for (y = 0; y < h; y++) {
 		unsigned char *d, *s, *m;
 		d = (unsigned char *) px;
@@ -855,6 +1108,36 @@ nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 (unsigned char *px, int w, int h, int rs, con
 /* RGB */
 
 void
+nr_R8G8B8_R8G8B8_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
+{
+	int r, c;
+
+	if (alpha == 0) return;
+
+	for (r = 0; r < h; r++) {
+		const unsigned char *s;
+		unsigned char *d;
+		d = px;
+		s = spx;
+		for (c = 0; c < w; c++) {
+			if (alpha == 255) {
+				d[0] = s[0];
+				d[1] = s[1];
+				d[2] = s[2];
+			} else {
+				d[0] = NR_COMPOSEN11 (s[0], alpha, d[0]);
+				d[1] = NR_COMPOSEN11 (s[1], alpha, d[1]);
+				d[2] = NR_COMPOSEN11 (s[2], alpha, d[2]);
+			}
+			d += 3;
+			s += 3;
+		}
+		px += rs;
+		spx += srs;
+	}
+}
+
+void
 nr_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
 {
 	int r, c;
diff --git a/src/libnr/nr-compose.h b/src/libnr/nr-compose.h
index 3fb1e5f..c3eafb9 100644
--- a/src/libnr/nr-compose.h
+++ b/src/libnr/nr-compose.h
@@ -12,24 +12,36 @@
 
 /* FINAL DST SRC */
 
+/* Destination A8 EMPTY */
+void nr_A8_EMPTY_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_A8_EMPTY_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_A8_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_A8_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+
+/* Destination R8G8B8 */
+void nr_R8G8B8_R8G8B8_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8_R8G8B8_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (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 (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 (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 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
 
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8 (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 (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 (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 (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 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
 
 /* FINAL DST SRC MASK */
+/* Destination R8G8B8A8 EMPTY */
+void nr_R8G8B8A8_N_EMPTY_A8_A8 (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_R8G8B8_A8 (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_N_A8 (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 (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_N_A8 (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 (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 (unsigned char *px, int w, int h, int rs,
 					const unsigned char *spx, int srs,
 					const unsigned char *mpx, int mrs);
@@ -62,10 +74,6 @@ void nr_R8G8B8_R8G8B8_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const
 void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 (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 (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 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
-void nr_R8G8B8_R8G8B8_R8G8B8A8_N (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 (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 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs);
 
diff --git a/src/libnr/nr-gradient.c b/src/libnr/nr-gradient.c
index 517948b..30e7531 100644
--- a/src/libnr/nr-gradient.c
+++ b/src/libnr/nr-gradient.c
@@ -246,7 +246,7 @@ nr_rgradient_render_generic_symmetric (NRRGradientRenderer *rgr, NRPixBlock *pb)
 					  (unsigned char *) rgr->vector,
 					  4 * NR_GRADIENT_VECTOR_LENGTH,
 					  0, 0);
-		bpp = (pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+		bpp = (pb->mode == NR_PIXBLOCK_MODE_G8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
 		for (y = pb->area.y0; y < pb->area.y1; y++) {
 			double gx, gy;
@@ -298,7 +298,7 @@ nr_rgradient_render_generic_optimized (NRRGradientRenderer *rgr, NRPixBlock *pb)
 				  (unsigned char *) rgr->vector,
 				  4 * NR_GRADIENT_VECTOR_LENGTH,
 				  0, 0);
-	bpp = (pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+	bpp = (pb->mode == NR_PIXBLOCK_MODE_G8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
 	r = MAX (rgr->r, 1e-9);
 
diff --git a/src/libnr/nr-pixblock-pattern.c b/src/libnr/nr-pixblock-pattern.c
index 7a0a173..56edbd8 100644
--- a/src/libnr/nr-pixblock-pattern.c
+++ b/src/libnr/nr-pixblock-pattern.c
@@ -50,7 +50,7 @@ nr_pixblock_render_gray_noise (NRPixBlock *pb, NRPixBlock *mask)
 			for (x = clip.x0; x < clip.x1; x++) {
 				v = v ^ noise[seed];
 				switch (pb->mode) {
-				case NR_PIXBLOCK_MODE_A8:
+				case NR_PIXBLOCK_MODE_G8:
 					d[0] = (65025 - (255 - m[0]) * (255 - d[0]) + 127) / 255;
 					break;
 				case NR_PIXBLOCK_MODE_R8G8B8:
@@ -94,7 +94,7 @@ nr_pixblock_render_gray_noise (NRPixBlock *pb, NRPixBlock *mask)
 			for (x = clip.x0; x < clip.x1; x++) {
 				v = v ^ noise[seed];
 				switch (pb->mode) {
-				case NR_PIXBLOCK_MODE_A8:
+				case NR_PIXBLOCK_MODE_G8:
 					d[0] = 255;
 					break;
 				case NR_PIXBLOCK_MODE_R8G8B8:
diff --git a/src/libnr/nr-pixblock-pixel.c b/src/libnr/nr-pixblock-pixel.c
index 2befa95..c500fe6 100644
--- a/src/libnr/nr-pixblock-pixel.c
+++ b/src/libnr/nr-pixblock-pixel.c
@@ -20,9 +20,9 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 	if (dpb->empty) {
 		/* Empty destination */
 		switch (dpb->mode) {
-		case NR_PIXBLOCK_MODE_A8:
+		case NR_PIXBLOCK_MODE_G8:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = 255;
@@ -39,7 +39,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
@@ -62,7 +62,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8A8N:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
@@ -94,7 +94,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8A8P:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
@@ -124,9 +124,9 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 	} else {
 		/* Image destination */
 		switch (dpb->mode) {
-		case NR_PIXBLOCK_MODE_A8:
+		case NR_PIXBLOCK_MODE_G8:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = 255;
@@ -143,7 +143,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
@@ -166,7 +166,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8A8N:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
@@ -199,7 +199,7 @@ nr_compose_pixblock_pixblock_pixel (NRPixBlock *dpb, unsigned char *d, const NRP
 			break;
 		case NR_PIXBLOCK_MODE_R8G8B8A8P:
 			switch (spb->mode) {
-			case NR_PIXBLOCK_MODE_A8:
+			case NR_PIXBLOCK_MODE_G8:
 				break;
 			case NR_PIXBLOCK_MODE_R8G8B8:
 				d[0] = s[0];
diff --git a/src/libnr/nr-pixblock.c b/src/libnr/nr-pixblock.c
index 8a52ecd..a26a561 100644
--- a/src/libnr/nr-pixblock.c
+++ b/src/libnr/nr-pixblock.c
@@ -14,8 +14,6 @@
 #include "nr-macros.h"
 #include "nr-pixblock.h"
 
-#define NR_TINY_MAX sizeof (unsigned char *)
-
 void
 nr_pixblock_setup_fast (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1, int clear)
 {
@@ -23,13 +21,20 @@ nr_pixblock_setup_fast (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1
 
 	w = x1 - x0;
 	h = y1 - y0;
-	bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+	bpp = NR_PIXBLOCK_MODE_BPP (mode);
 
-	size = bpp * w * h;
+	pb->mode = mode;
+	pb->area.x0 = x0;
+	pb->area.y0 = y0;
+	pb->area.x1 = x1;
+	pb->area.y1 = y1;
+	pb->rs = (bpp * w + 3) & 0xfffffffc;
+
+	size = h * pb->rs;
 
 	if (size <= NR_TINY_MAX) {
 		pb->size = NR_PIXBLOCK_SIZE_TINY;
-		if (clear) memset (pb->data.p, 0x0, size);
+		if (clear && size) memset (pb->data.p, 0x0, size);
 	} else if (size <= 4096) {
 		pb->size = NR_PIXBLOCK_SIZE_4K;
 		pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
@@ -45,13 +50,7 @@ nr_pixblock_setup_fast (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1
 		if (clear) memset (pb->data.px, 0x0, size);
 	}
 
-	pb->mode = mode;
 	pb->empty = 1;
-	pb->area.x0 = x0;
-	pb->area.y0 = y0;
-	pb->area.x1 = x1;
-	pb->area.y1 = y1;
-	pb->rs = bpp * w;
 }
 
 void
@@ -61,26 +60,27 @@ nr_pixblock_setup (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1, int
 
 	w = x1 - x0;
 	h = y1 - y0;
-	bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+	bpp = NR_PIXBLOCK_MODE_BPP (mode);
+
+	pb->mode = mode;
+	pb->area.x0 = x0;
+	pb->area.y0 = y0;
+	pb->area.x1 = x1;
+	pb->area.y1 = y1;
+	pb->rs = (bpp * w + 3) & 0xfffffffc;
 
-	size = bpp * w * h;
+	size = h * pb->rs;
 
 	if (size <= NR_TINY_MAX) {
 		pb->size = NR_PIXBLOCK_SIZE_TINY;
-		if (clear) memset (pb->data.p, 0x0, size);
+		if (clear && size) memset (pb->data.p, 0x0, size);
 	} else {
 		pb->size = NR_PIXBLOCK_SIZE_BIG;
 		pb->data.px = nr_new (unsigned char, size);
 		if (clear) memset (pb->data.px, 0x0, size);
 	}
 
-	pb->mode = mode;
 	pb->empty = 1;
-	pb->area.x0 = x0;
-	pb->area.y0 = y0;
-	pb->area.x1 = x1;
-	pb->area.y1 = y1;
-	pb->rs = bpp * w;
 }
 
 void
@@ -89,7 +89,7 @@ nr_pixblock_setup_extern (NRPixBlock *pb, int mode, int x0, int y0, int x1, int
 	int w, bpp;
 
 	w = x1 - x0;
-	bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
+	bpp = (mode == NR_PIXBLOCK_MODE_G8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
 
 	pb->size = NR_PIXBLOCK_SIZE_STATIC;
 	pb->mode = mode;
@@ -160,6 +160,172 @@ nr_pixblock_free (NRPixBlock *pb)
 	return NULL;
 }
 
+/* Helpers */
+
+unsigned int
+nr_pixblock_has_alpha (const NRPixBlock *pb)
+{
+	if (!pb) return 0;
+	if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) return 1;
+	if (pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) return 1;
+	return 0;
+}
+
+void
+nr_pixblock_get_channel_limits (const NRPixBlock *pb, unsigned int minv[], unsigned int maxv[])
+{
+	int x, y, bpp, c;
+	bpp = NR_PIXBLOCK_BPP(pb);
+	for (c = 0; c < bpp; c++) {
+		minv[c] = 255;
+		maxv[c] = 0;
+	}
+	for (y = pb->area.y0; y < pb->area.y1; y++) {
+		const unsigned char *s;
+		s = NR_PIXBLOCK_PX (pb) + (y - pb->area.y0) * pb->rs;
+		for (x = pb->area.x0; x < pb->area.x1; x++) {
+			for (c = 0; c < bpp; c++) {
+				if (s[c] < minv[c]) minv[c] = s[c];
+				if (s[c] > maxv[c]) maxv[c] = s[c];
+			}
+			s += bpp;
+		}
+	}
+}
+
+void
+nr_pixblock_get_histogram (const NRPixBlock *pb, unsigned int histogram[][256])
+{
+	int x, y, bpp, c, v;
+	bpp = NR_PIXBLOCK_BPP(pb);
+	for (c = 0; c < bpp; c++) {
+		for (v = 0; v < 256; v++) histogram[c][v] = 0;
+	}
+	for (y = pb->area.y0; y < pb->area.y1; y++) {
+		const unsigned char *s;
+		s = NR_PIXBLOCK_PX (pb) + (y - pb->area.y0) * pb->rs;
+		for (x = pb->area.x0; x < pb->area.x1; x++) {
+			for (c = 0; c < bpp; c++) {
+				histogram[c][s[c]] += 1;
+			}
+			s += bpp;
+		}
+	}
+}
+
+unsigned int
+nr_pixblock_get_crc32 (const NRPixBlock *pb)
+{
+	unsigned int crc32, acc;
+	unsigned int width, height, bpp, x, y, c, cnt;
+	width = pb->area.x1 - pb->area.x0;
+	height = pb->area.y1 - pb->area.y0;
+	bpp = NR_PIXBLOCK_BPP(pb);
+	crc32 = 0;
+	acc = 0;
+	cnt = 0;
+	for (y = 0; y < height; y++) {
+		const unsigned char *s = NR_PIXBLOCK_ROW(pb, y);
+		for (x = 0; x < width; x++) {
+			for (c = 0; c < bpp; c++) {
+				acc <<= 8;
+				acc |= *s++;
+				if (++cnt >= 4) {
+					crc32 ^= acc;
+					acc = cnt = 0;
+				}
+			}
+		}
+		crc32 ^= acc;
+		acc = cnt = 0;
+	}
+	return crc32;
+}
+
+NRULongLong
+nr_pixblock_get_crc64 (const NRPixBlock *pb)
+{
+	NRULongLong crc64, acc, carry;
+	unsigned int width, height, bpp, x, y, c, cnt;
+	width = pb->area.x1 - pb->area.x0;
+	height = pb->area.y1 - pb->area.y0;
+	bpp = NR_PIXBLOCK_BPP(pb);
+	crc64 = 0;
+	acc = 0;
+	carry = 0;
+	cnt = 0;
+	for (y = 0; y < height; y++) {
+		const unsigned char *s = NR_PIXBLOCK_ROW(pb, y);
+		for (x = 0; x < width; x++) {
+			for (c = 0; c < bpp; c++) {
+				acc <<= 8;
+				acc |= *s++;
+				if (++cnt >= 8) {
+					if ((crc64 & 0x8000000000000000) && (acc & 0x8000000000000000)) carry = 1;
+					crc64 += acc;
+					crc64 += carry;
+					acc = carry = 0;
+					cnt = 0;
+				}
+			}
+		}
+		crc64 += acc;
+		acc = cnt = 0;
+	}
+	return crc64;
+}
+
+unsigned int
+nr_pixblock_get_hash (const NRPixBlock *pb)
+{
+	unsigned int hval;
+	unsigned int width, height, bpp, x, y, c;
+	width = pb->area.x1 - pb->area.x0;
+	height = pb->area.y1 - pb->area.y0;
+	bpp = NR_PIXBLOCK_BPP(pb);
+	hval = pb->mode;
+	hval = (hval << 5) - hval + pb->empty;
+	hval = (hval << 5) - hval + pb->area.x0;
+	hval = (hval << 5) - hval + pb->area.y0;
+	hval = (hval << 5) - hval + pb->area.x1;
+	hval = (hval << 5) - hval + pb->area.y1;
+	for (y = 0; y < height; y++) {
+		const unsigned char *s = NR_PIXBLOCK_ROW(pb, y);
+		for (x = 0; x < width; x++) {
+			for (c = 0; c < bpp; c++) {
+				hval = (hval << 5) - hval + *s++;
+			}
+		}
+	}
+	return hval;
+}
+
+unsigned int
+nr_pixblock_is_equal (const NRPixBlock *a, const NRPixBlock *b)
+{
+	unsigned int width, height, bpp, x, y, c;
+	if (a == b) return 1;
+	if (a->mode != b->mode) return 0;
+	if (a->empty != b->empty) return 0;
+	if (a->area.x0 - b->area.x0) return 0;
+	if (a->area.y0 - b->area.y0) return 0;
+	if (a->area.x1 - b->area.x1) return 0;
+	if (a->area.y1 - b->area.y1) return 0;
+	width = a->area.x1 - a->area.x0;
+	height = a->area.y1 - a->area.y0;
+	bpp = NR_PIXBLOCK_BPP(a);
+	for (y = 0; y < height; y++) {
+		const unsigned char *pa = NR_PIXBLOCK_ROW(a, y);
+		const unsigned char *pb = NR_PIXBLOCK_ROW(b, y);
+		for (x = 0; x < width; x++) {
+			for (c = 0; c < bpp; c++) {
+				if (*pa++ != *pb++) return 0;
+			}
+		}
+	}
+	return 1;
+}
+
 /* PixelStore operations */
 
 #define NR_4K_BLOCK 32
diff --git a/src/libnr/nr-pixblock.h b/src/libnr/nr-pixblock.h
index 3b50475..813e67d 100644
--- a/src/libnr/nr-pixblock.h
+++ b/src/libnr/nr-pixblock.h
@@ -10,6 +10,8 @@
  * This code is in public domain
  */
 
+#include <assert.h>
+
 #include <libnr/nr-types.h>
 #include <libnr/nr-forward.h>
 
@@ -17,8 +19,10 @@
 extern "C" {
 #endif
 
+#define NR_TINY_MAX 64
+
 enum {
-	NR_PIXBLOCK_SIZE_TINY, /* Fits in (unsigned char *) */
+	NR_PIXBLOCK_SIZE_TINY, /* Fits in pixblock data */
 	NR_PIXBLOCK_SIZE_4K, /* Pixelstore */
 	NR_PIXBLOCK_SIZE_16K, /* Pixelstore */
 	NR_PIXBLOCK_SIZE_64K, /* Pixelstore */
@@ -27,12 +31,14 @@ enum {
 };
 
 enum {
-	NR_PIXBLOCK_MODE_A8, /* Grayscale */
+	NR_PIXBLOCK_MODE_G8, /* Grayscale or mask */
 	NR_PIXBLOCK_MODE_R8G8B8, /* 8 bit RGB */
 	NR_PIXBLOCK_MODE_R8G8B8A8N, /* Normal 8 bit RGBA */
 	NR_PIXBLOCK_MODE_R8G8B8A8P /* Premultiplied 8 bit RGBA */
 };
 
+// Automatically allocated rowstride is aligned at 4 bytes
+
 struct _NRPixBlock {
 	unsigned int size : 3;
 	unsigned int mode : 2;
@@ -41,12 +47,14 @@ struct _NRPixBlock {
 	NRRectS area;
 	union {
 		unsigned char *px;
-		unsigned char p[sizeof (unsigned char *)];
+		unsigned char p[NR_TINY_MAX];
 	} data;
 };
 
-#define NR_PIXBLOCK_BPP(pb) (((pb)->mode == NR_PIXBLOCK_MODE_A8) ? 1 : ((pb)->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4)
+#define NR_PIXBLOCK_MODE_BPP(m) ((m == NR_PIXBLOCK_MODE_G8) ? 1 : (m == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4)
+#define NR_PIXBLOCK_BPP(pb) (((pb)->mode == NR_PIXBLOCK_MODE_G8) ? 1 : ((pb)->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4)
 #define NR_PIXBLOCK_PX(pb) (((pb)->size == NR_PIXBLOCK_SIZE_TINY) ? (pb)->data.p : (pb)->data.px)
+#define NR_PIXBLOCK_ROW(pb,r) (NR_PIXBLOCK_PX (pb) + (r) * (pb)->rs)
 
 void nr_pixblock_setup (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1, int clear);
 void nr_pixblock_setup_fast (NRPixBlock *pb, int mode, int x0, int y0, int x1, int y1, int clear);
@@ -56,6 +64,18 @@ void nr_pixblock_release (NRPixBlock *pb);
 NRPixBlock *nr_pixblock_new (int mode, int x0, int y0, int x1, int y1, int clear);
 NRPixBlock *nr_pixblock_free (NRPixBlock *pb);
 
+/* Helpers */
+
+unsigned int nr_pixblock_has_alpha (const NRPixBlock *pb);
+void nr_pixblock_get_channel_limits (const NRPixBlock *pb, unsigned int minv[], unsigned int maxv[]);
+void nr_pixblock_get_histogram (const NRPixBlock *pb, unsigned int histogram[][256]);
+unsigned int nr_pixblock_get_crc32 (const NRPixBlock *pb);
+NRULongLong nr_pixblock_get_crc64 (const NRPixBlock *pb);
+unsigned int nr_pixblock_get_hash (const NRPixBlock *pb);
+unsigned int nr_pixblock_is_equal (const NRPixBlock *a, const NRPixBlock *b);
+
+/* Memory management */
+
 unsigned char *nr_pixelstore_4K_new (int clear, unsigned char val);
 void nr_pixelstore_4K_free (unsigned char *px);
 unsigned char *nr_pixelstore_16K_new (int clear, unsigned char val);
diff --git a/src/libnr/nr-types.h b/src/libnr/nr-types.h
index 3231255..e6cee77 100644
--- a/src/libnr/nr-types.h
+++ b/src/libnr/nr-types.h
@@ -23,6 +23,7 @@ typedef int16_t NRShort;
 typedef uint16_t NRUShort;
 typedef int32_t NRLong;
 typedef uint32_t NRULong;
+typedef uint64_t NRULongLong;
 #else
 #ifdef HAVE_NR_CONFIG_H
 /* Automake based systems */
@@ -35,6 +36,7 @@ typedef signed short NRShort;
 typedef unsigned short NRUShort;
 typedef signed int NRLong;
 typedef unsigned int NRULong;
+typedef unsigned __int64 NRULongLong;
 #endif
 #endif
 
diff --git a/src/libnr/testnr.c b/src/libnr/testnr.c
index 85457ec..66b4c5d 100644
--- a/src/libnr/testnr.c
+++ b/src/libnr/testnr.c
@@ -67,7 +67,7 @@ main (int argc, const char **argv)
 	/* Masks */
 	for (i = 0; i < 16; i++) {
 		int r, b, c;
-		nr_pixblock_setup_fast (&m[i], NR_PIXBLOCK_MODE_A8, 0, 0, 64, 64, 0);
+		nr_pixblock_setup_fast (&m[i], NR_PIXBLOCK_MODE_G8, 0, 0, 64, 64, 0);
 		for (r = 0; r < 64; r++) {
 			unsigned int q;
 			unsigned char *p;
diff --git a/src/libnrtype/nr-rasterfont.c b/src/libnrtype/nr-rasterfont.c
index 9aa3c8f..7d032b6 100644
--- a/src/libnrtype/nr-rasterfont.c
+++ b/src/libnrtype/nr-rasterfont.c
@@ -260,7 +260,7 @@ nr_rasterfont_generic_glyph_mask_render (NRRasterFont *rf, unsigned int glyph, N
 		area.y1 = NRRF_COORD_INT_UPPER (slot->glyph.ig.bbox.y1) + sy;
 		break;
 	case NRRF_TYPE_SVP:
-		nr_pixblock_setup_extern (&spb, NR_PIXBLOCK_MODE_A8,
+		nr_pixblock_setup_extern (&spb, NR_PIXBLOCK_MODE_G8,
 					  m->area.x0 - sx, m->area.y0 - sy, m->area.x1 - sx, m->area.y1 - sy,
 					  NR_PIXBLOCK_PX (m), m->rs, FALSE, FALSE);
 		nr_pixblock_render_svp_mask_or (&spb, slot->glyph.sg.svp);
@@ -383,7 +383,7 @@ nr_rasterfont_ensure_glyph_slot (NRRasterFont *rf, unsigned int glyph, unsigned
 					slot->glyph.ig.bbox.x1 = MIN (x1, 32767);
 					slot->glyph.ig.bbox.y1 = MIN (y1, 32767);
 					slot->glyph.ig.px = nr_new (unsigned char, w * h);
-					nr_pixblock_setup_extern (&spb, NR_PIXBLOCK_MODE_A8,
+					nr_pixblock_setup_extern (&spb, NR_PIXBLOCK_MODE_G8,
 								  NRRF_COORD_INT_LOWER (x0),
 								  NRRF_COORD_INT_LOWER (y0),
 								  NRRF_COORD_INT_UPPER (x1),
diff --git a/src/widgets/font-selector.c b/src/widgets/font-selector.c
index 0239738..4abd949 100644
--- a/src/widgets/font-selector.c
+++ b/src/widgets/font-selector.c
@@ -594,7 +594,7 @@ sp_font_preview_expose (GtkWidget *widget, GdkEventExpose *event)
 					y1 = MIN (y0 + 64, event->area.y + event->area.height);
 					ps = nr_pixelstore_16K_new (TRUE, 0xff);
 					nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8, x0, y0, x1, y1, ps, 3 * (x1 - x0), FALSE, FALSE);
-					nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_A8, x0, y0, x1, y1, TRUE);
+					nr_pixblock_setup_fast (&m, NR_PIXBLOCK_MODE_G8, x0, y0, x1, y1, TRUE);
 					pb.empty = FALSE;
 					for (i = 0; i < len; i++) {
 						nr_rasterfont_glyph_mask_render (fprev->rfont, glyphs[i], &m, hpos[i] + startx, starty);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]