<commit_before>#include "fitz.h"

#define LINEAR

typedef unsigned char byte;

static inline float roundup(float x)
{
	return (x < 0) ? floorf(x) : ceilf(x);
}

#ifdef LINEAR

static inline int lerp(int a, int b, int t)
{
	return a + (((b - a) * t) >> 16);
}

static inline int bilerp(int a, int b, int c, int d, int u, int v)
{
	return lerp(lerp(a, b, u), lerp(c, d, u), v);
}

static inline byte *samplenearest(byte *s, int w, int h, int n, int u, int v)
{
	if (u < 0) u = 0;
	if (v < 0) v = 0;
	if (u >= w) u = w - 1;
	if (v >= h) v = h - 1;
	return s + (v * w + u) * n;
}

#endif

/* Blend premultiplied source image in constant alpha over destination */

static inline void
fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha)
{
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, n, ui, vi);
			byte *b = samplenearest(sp, sw, sh, n, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, n, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1);
			int x = bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf);
			int t = 255 - fz_mul255(x, alpha);
			for (k = 0; k < n; k++)
			{
				x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
				dp[k] = x + fz_mul255(dp[k], t);
			}
#else
			byte *sample = sp + ((vi * sw + ui) * n);
			int t = 255 - fz_mul255(sample[n-1], alpha);
			for (k = 0; k < n; k++)
				dp[k] = sample[k] + fz_mul255(dp[k], t);
#endif
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

/* Blend premultiplied source image over destination */

static inline void
fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n)
{
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, n, ui, vi);
			byte *b = samplenearest(sp, sw, sh, n, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, n, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1);
			int t = 255 - bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf);
			for (k = 0; k < n; k++)
			{
				int x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
				dp[k] = x + fz_mul255(dp[k], t);
			}
#else
			byte *sample = sp + ((vi * sw + ui) * n);
			int t = 255 - sample[n-1];
			for (k = 0; k < n; k++)
				dp[k] = sample[k] + fz_mul255(dp[k], t);
#endif
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

/* Blend non-premultiplied color in source image mask over destination */

static inline void
fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color)
{
	int sa = color[n-1];
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, 1, ui, vi);
			byte *b = samplenearest(sp, sw, sh, 1, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, 1, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, 1, ui+1, vi+1);
			int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf);
#else
			int ma = sp[vi * sw + ui];
#endif
			int masa = FZ_COMBINE(FZ_EXPAND(ma), sa);
			for (k = 0; k < n - 1; k++)
				dp[k] = FZ_BLEND(color[k], dp[k], masa);
			dp[k] = FZ_BLEND(255, dp[k], masa);
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

void
fz_paintaffine(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha)
{
	if (alpha == 255)
	{
		switch (n)
		{
			case 1: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 1); break;
			case 2: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 2); break;
			case 4: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 4); break;
			default: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, n); break;
		}
	}
	else	if (alpha > 0)<commit_msg>Fix bug where image with alpha painting was not multiplying colors with the constant alpha.<commit_after>#include "fitz.h"

#define LINEAR

typedef unsigned char byte;

static inline float roundup(float x)
{
	return (x < 0) ? floorf(x) : ceilf(x);
}

#ifdef LINEAR

static inline int lerp(int a, int b, int t)
{
	return a + (((b - a) * t) >> 16);
}

static inline int bilerp(int a, int b, int c, int d, int u, int v)
{
	return lerp(lerp(a, b, u), lerp(c, d, u), v);
}

static inline byte *samplenearest(byte *s, int w, int h, int n, int u, int v)
{
	if (u < 0) u = 0;
	if (v < 0) v = 0;
	if (u >= w) u = w - 1;
	if (v >= h) v = h - 1;
	return s + (v * w + u) * n;
}

#endif

/* Blend premultiplied source image in constant alpha over destination */

static inline void
fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha)
{
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, n, ui, vi);
			byte *b = samplenearest(sp, sw, sh, n, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, n, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1);
			int x = bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf);
			int t = 255 - fz_mul255(x, alpha);
			for (k = 0; k < n; k++)
			{
				x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
				dp[k] = fz_mul255(x, alpha) + fz_mul255(dp[k], t);
			}
#else
			byte *sample = sp + ((vi * sw + ui) * n);
			int t = 255 - fz_mul255(sample[n-1], alpha);
			for (k = 0; k < n; k++)
				dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t);
#endif
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

/* Blend premultiplied source image over destination */

static inline void
fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n)
{
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, n, ui, vi);
			byte *b = samplenearest(sp, sw, sh, n, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, n, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, n, ui+1, vi+1);
			int t = 255 - bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf);
			for (k = 0; k < n; k++)
			{
				int x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
				dp[k] = x + fz_mul255(dp[k], t);
			}
#else
			byte *sample = sp + ((vi * sw + ui) * n);
			int t = 255 - sample[n-1];
			for (k = 0; k < n; k++)
				dp[k] = sample[k] + fz_mul255(dp[k], t);
#endif
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

/* Blend non-premultiplied color in source image mask over destination */

static inline void
fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color)
{
	int sa = color[n-1];
	int k;

	while (w--)
	{
		int ui = u >> 16;
		int vi = v >> 16;
		if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
		{
#ifdef LINEAR
			int uf = u & 0xffff;
			int vf = v & 0xffff;
			byte *a = samplenearest(sp, sw, sh, 1, ui, vi);
			byte *b = samplenearest(sp, sw, sh, 1, ui+1, vi);
			byte *c = samplenearest(sp, sw, sh, 1, ui, vi+1);
			byte *d = samplenearest(sp, sw, sh, 1, ui+1, vi+1);
			int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf);
#else
			int ma = sp[vi * sw + ui];
#endif
			int masa = FZ_COMBINE(FZ_EXPAND(ma), sa);
			for (k = 0; k < n - 1; k++)
				dp[k] = FZ_BLEND(color[k], dp[k], masa);
			dp[k] = FZ_BLEND(255, dp[k], masa);
		}
		dp += n;
		u += fa;
		v += fb;
	}
}

void
fz_paintaffine(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha)
{
	if (alpha == 255)
	{
		switch (n)
		{
			case 1: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 1); break;
			case 2: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 2); break;
			case 4: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 4); break;
			default: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, n); break;
		}
	}
	else if (alpha > 0)
{'fraction_non_alphanumeric': 0.19829081000743126, 'fraction_numerical': 0.028734208570720832, 'mean_word_length': 2.6704545454545454, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5168927', 'n_tokens_mistral': 4268, 'n_tokens_neox': 3767, 'n_words': 1275}