Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
 
3
/*
4
 
5
The functions in this file implement various flavours of Porter-Duff blending.
6
 
7
We take the following as definitions:
8
 
9
	Cx = Color (from plane x)
10
	ax = Alpha (from plane x)
11
	cx = Cx.ax = Premultiplied color (from plane x)
12
 
13
The general PorterDuff blending equation is:
14
 
15
	Blend Z = X op Y	cz = Fx.cx + Fy. cy	where Fx and Fy depend on op
16
 
17
The two operations we use in this file are: '(X in Y) over Z' and
18
'S over Z'. The definitions of the 'over' and 'in' operations are as
19
follows:
20
 
21
	For S over Z,	Fs = 1, Fz = 1-as
22
	For X in Y,	Fx = ay, Fy = 0
23
 
24
We have 2 choices; we can either work with premultiplied data, or non
25
premultiplied data. Our
26
 
27
First the premultiplied case:
28
 
29
	Let S = (X in Y)
30
	Let R = (X in Y) over Z = S over Z
31
 
32
	cs	= cx.Fx + cy.Fy	(where Fx = ay, Fy = 0)
33
		= cx.ay
34
	as	= ax.Fx + ay.Fy
35
		= ax.ay
36
 
37
	cr	= cs.Fs + cz.Fz	(where Fs = 1, Fz = 1-as)
38
		= cs + cz.(1-as)
39
		= cx.ay + cz.(1-ax.ay)
40
	ar	= as.Fs + az.Fz
41
		= as + az.(1-as)
42
		= ax.ay + az.(1-ax.ay)
43
 
44
This has various nice properties, like not needing any divisions, and
45
being symmetric in color and alpha, so this is what we use. Because we
46
went through the pain of deriving the non premultiplied forms, we list
47
them here too, though they are not used.
48
 
49
Non Pre-multiplied case:
50
 
51
	Cs.as	= Fx.Cx.ax + Fy.Cy.ay	(where Fx = ay, Fy = 0)
52
		= Cx.ay.ax
53
	Cs	= (Cx.ay.ax)/(ay.ax)
54
		= Cx
55
	Cr.ar	= Fs.Cs.as + Fz.Cz.az	(where Fs = 1, Fz = 1-as)
56
		= Cs.as	+ (1-as).Cz.az
57
		= Cx.ax.ay + Cz.az.(1-ax.ay)
58
	Cr	= (Cx.ax.ay + Cz.az.(1-ax.ay))/(ax.ay + az.(1-ax-ay))
59
 
60
Much more complex, it seems. However, if we could restrict ourselves to
61
the case where we were always plotting onto an opaque background (i.e.
62
az = 1), then:
63
 
64
	Cr	= Cx.(ax.ay) + Cz.(1-ax.ay)
65
		= (Cx-Cz)*(1-ax.ay) + Cz	(a single MLA operation)
66
	ar	= 1
67
 
68
Sadly, this is not true in the general case, so we abandon this effort
69
and stick to using the premultiplied form.
70
 
71
*/
72
 
73
typedef unsigned char byte;
74
 
75
/* These are used by the non-aa scan converter */
76
 
77
void
78
fz_paint_solid_alpha(byte * restrict dp, int w, int alpha)
79
{
80
	int t = FZ_EXPAND(255 - alpha);
81
	while (w--)
82
	{
83
		*dp = alpha + FZ_COMBINE(*dp, t);
84
		dp ++;
85
	}
86
}
87
 
88
void
89
fz_paint_solid_color(byte * restrict dp, int n, int w, byte *color)
90
{
91
	int n1 = n - 1;
92
	int sa = FZ_EXPAND(color[n1]);
93
	int k;
94
	while (w--)
95
	{
96
		int ma = FZ_COMBINE(FZ_EXPAND(255), sa);
97
		for (k = 0; k < n1; k++)
98
			dp[k] = FZ_BLEND(color[k], dp[k], ma);
99
		dp[k] = FZ_BLEND(255, dp[k], ma);
100
		dp += n;
101
	}
102
}
103
 
104
/* Blend a non-premultiplied color in mask over destination */
105
 
106
static inline void
107
fz_paint_span_with_color_2(byte * restrict dp, byte * restrict mp, int w, byte *color)
108
{
109
	int sa = FZ_EXPAND(color[1]);
110
	int g = color[0];
111
	while (w--)
112
	{
113
		int ma = *mp++;
114
		ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
115
		dp[0] = FZ_BLEND(g, dp[0], ma);
116
		dp[1] = FZ_BLEND(255, dp[1], ma);
117
		dp += 2;
118
	}
119
}
120
 
121
static inline void
122
fz_paint_span_with_color_4(byte * restrict dp, byte * restrict mp, int w, byte *color)
123
{
124
	int sa = FZ_EXPAND(color[3]);
125
	int r = color[0];
126
	int g = color[1];
127
	int b = color[2];
128
	while (w--)
129
	{
130
		int ma = *mp++;
131
		ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
132
		dp[0] = FZ_BLEND(r, dp[0], ma);
133
		dp[1] = FZ_BLEND(g, dp[1], ma);
134
		dp[2] = FZ_BLEND(b, dp[2], ma);
135
		dp[3] = FZ_BLEND(255, dp[3], ma);
136
		dp += 4;
137
	}
138
}
139
 
140
static inline void
141
fz_paint_span_with_color_N(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
142
{
143
	int n1 = n - 1;
144
	int sa = FZ_EXPAND(color[n1]);
145
	int k;
146
	while (w--)
147
	{
148
		int ma = *mp++;
149
		ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
150
		for (k = 0; k < n1; k++)
151
			dp[k] = FZ_BLEND(color[k], dp[k], ma);
152
		dp[k] = FZ_BLEND(255, dp[k], ma);
153
		dp += n;
154
	}
155
}
156
 
157
void
158
fz_paint_span_with_color(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
159
{
160
	switch (n)
161
	{
162
	case 2: fz_paint_span_with_color_2(dp, mp, w, color); break;
163
	case 4: fz_paint_span_with_color_4(dp, mp, w, color); break;
164
	default: fz_paint_span_with_color_N(dp, mp, n, w, color); break;
165
	}
166
}
167
 
168
/* Blend source in mask over destination */
169
 
170
static inline void
171
fz_paint_span_with_mask_2(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
172
{
173
	while (w--)
174
	{
175
		int masa;
176
		int ma = *mp++;
177
		ma = FZ_EXPAND(ma);
178
		masa = FZ_COMBINE(sp[1], ma);
179
		masa = 255 - masa;
180
		masa = FZ_EXPAND(masa);
181
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
182
		sp++; dp++;
183
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
184
		sp++; dp++;
185
	}
186
}
187
 
188
static inline void
189
fz_paint_span_with_mask_4(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
190
{
191
	while (w--)
192
	{
193
		int masa;
194
		int ma = *mp++;
195
		ma = FZ_EXPAND(ma);
196
		masa = FZ_COMBINE(sp[3], ma);
197
		masa = 255 - masa;
198
		masa = FZ_EXPAND(masa);
199
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
200
		sp++; dp++;
201
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
202
		sp++; dp++;
203
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
204
		sp++; dp++;
205
		*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
206
		sp++; dp++;
207
	}
208
}
209
 
210
static inline void
211
fz_paint_span_with_mask_N(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
212
{
213
	while (w--)
214
	{
215
		int k = n;
216
		int masa;
217
		int ma = *mp++;
218
		ma = FZ_EXPAND(ma);
219
		masa = FZ_COMBINE(sp[n-1], ma);
220
		masa = 255-masa;
221
		masa = FZ_EXPAND(masa);
222
		while (k--)
223
		{
224
			*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
225
			sp++; dp++;
226
		}
227
	}
228
}
229
 
230
static void
231
fz_paint_span_with_mask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
232
{
233
	switch (n)
234
	{
235
	case 2: fz_paint_span_with_mask_2(dp, sp, mp, w); break;
236
	case 4: fz_paint_span_with_mask_4(dp, sp, mp, w); break;
237
	default: fz_paint_span_with_mask_N(dp, sp, mp, n, w); break;
238
	}
239
}
240
 
241
/* Blend source in constant alpha over destination */
242
 
243
static inline void
244
fz_paint_span_2_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
245
{
246
	alpha = FZ_EXPAND(alpha);
247
	while (w--)
248
	{
249
		int masa = FZ_COMBINE(sp[1], alpha);
250
		*dp = FZ_BLEND(*sp, *dp, masa);
251
		dp++; sp++;
252
		*dp = FZ_BLEND(*sp, *dp, masa);
253
		dp++; sp++;
254
	}
255
}
256
 
257
static inline void
258
fz_paint_span_4_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
259
{
260
	alpha = FZ_EXPAND(alpha);
261
	while (w--)
262
	{
263
		int masa = FZ_COMBINE(sp[3], alpha);
264
		*dp = FZ_BLEND(*sp, *dp, masa);
265
		sp++; dp++;
266
		*dp = FZ_BLEND(*sp, *dp, masa);
267
		sp++; dp++;
268
		*dp = FZ_BLEND(*sp, *dp, masa);
269
		sp++; dp++;
270
		*dp = FZ_BLEND(*sp, *dp, masa);
271
		sp++; dp++;
272
	}
273
}
274
 
275
static inline void
276
fz_paint_span_N_with_alpha(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
277
{
278
	alpha = FZ_EXPAND(alpha);
279
	while (w--)
280
	{
281
		int masa = FZ_COMBINE(sp[n-1], alpha);
282
		int k = n;
283
		while (k--)
284
		{
285
			*dp = FZ_BLEND(*sp++, *dp, masa);
286
			dp++;
287
		}
288
	}
289
}
290
 
291
/* Blend source over destination */
292
 
293
static inline void
294
fz_paint_span_1(byte * restrict dp, byte * restrict sp, int w)
295
{
296
	while (w--)
297
	{
298
		int t = FZ_EXPAND(255 - sp[0]);
299
		*dp = *sp++ + FZ_COMBINE(*dp, t);
300
		dp ++;
301
	}
302
}
303
 
304
static inline void
305
fz_paint_span_2(byte * restrict dp, byte * restrict sp, int w)
306
{
307
	while (w--)
308
	{
309
		int t = FZ_EXPAND(255 - sp[1]);
310
		*dp = *sp++ + FZ_COMBINE(*dp, t);
311
		dp++;
312
		*dp = *sp++ + FZ_COMBINE(*dp, t);
313
		dp++;
314
	}
315
}
316
 
317
static inline void
318
fz_paint_span_4(byte * restrict dp, byte * restrict sp, int w)
319
{
320
	while (w--)
321
	{
322
		int t = FZ_EXPAND(255 - sp[3]);
323
		*dp = *sp++ + FZ_COMBINE(*dp, t);
324
		dp++;
325
		*dp = *sp++ + FZ_COMBINE(*dp, t);
326
		dp++;
327
		*dp = *sp++ + FZ_COMBINE(*dp, t);
328
		dp++;
329
		*dp = *sp++ + FZ_COMBINE(*dp, t);
330
		dp++;
331
	}
332
}
333
 
334
static inline void
335
fz_paint_span_N(byte * restrict dp, byte * restrict sp, int n, int w)
336
{
337
	while (w--)
338
	{
339
		int k = n;
340
		int t = FZ_EXPAND(255 - sp[n-1]);
341
		while (k--)
342
		{
343
			*dp = *sp++ + FZ_COMBINE(*dp, t);
344
			dp++;
345
		}
346
	}
347
}
348
 
349
void
350
fz_paint_span(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
351
{
352
	if (alpha == 255)
353
	{
354
		switch (n)
355
		{
356
		case 1: fz_paint_span_1(dp, sp, w); break;
357
		case 2: fz_paint_span_2(dp, sp, w); break;
358
		case 4: fz_paint_span_4(dp, sp, w); break;
359
		default: fz_paint_span_N(dp, sp, n, w); break;
360
		}
361
	}
362
	else if (alpha > 0)
363
	{
364
		switch (n)
365
		{
366
		case 2: fz_paint_span_2_with_alpha(dp, sp, w, alpha); break;
367
		case 4: fz_paint_span_4_with_alpha(dp, sp, w, alpha); break;
368
		default: fz_paint_span_N_with_alpha(dp, sp, n, w, alpha); break;
369
		}
370
	}
371
}
372
 
373
/*
374
 * Pixmap blending functions
375
 */
376
 
377
void
378
fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox)
379
{
380
	unsigned char *sp, *dp;
381
	int x, y, w, h, n;
382
 
383
	assert(dst->n == src->n);
384
 
385
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(dst));
386
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
387
 
388
	x = bbox.x0;
389
	y = bbox.y0;
390
	w = bbox.x1 - bbox.x0;
391
	h = bbox.y1 - bbox.y0;
392
	if ((w | h) == 0)
393
		return;
394
 
395
	n = src->n;
396
	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
397
	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
398
 
399
	while (h--)
400
	{
401
		fz_paint_span(dp, sp, n, w, alpha);
402
		sp += src->w * n;
403
		dp += dst->w * n;
404
	}
405
}
406
 
407
void
408
fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha)
409
{
410
	unsigned char *sp, *dp;
411
	fz_bbox bbox;
412
	int x, y, w, h, n;
413
 
414
	assert(dst->n == src->n);
415
 
416
	bbox = fz_bound_pixmap(dst);
417
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
418
 
419
	x = bbox.x0;
420
	y = bbox.y0;
421
	w = bbox.x1 - bbox.x0;
422
	h = bbox.y1 - bbox.y0;
423
	if ((w | h) == 0)
424
		return;
425
 
426
	n = src->n;
427
	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
428
	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
429
 
430
	while (h--)
431
	{
432
		fz_paint_span(dp, sp, n, w, alpha);
433
		sp += src->w * n;
434
		dp += dst->w * n;
435
	}
436
}
437
 
438
void
439
fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk)
440
{
441
	unsigned char *sp, *dp, *mp;
442
	fz_bbox bbox;
443
	int x, y, w, h, n;
444
 
445
	assert(dst->n == src->n);
446
	assert(msk->n == 1);
447
 
448
	bbox = fz_bound_pixmap(dst);
449
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
450
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(msk));
451
 
452
	x = bbox.x0;
453
	y = bbox.y0;
454
	w = bbox.x1 - bbox.x0;
455
	h = bbox.y1 - bbox.y0;
456
	if ((w | h) == 0)
457
		return;
458
 
459
	n = src->n;
460
	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n;
461
	mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n;
462
	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n;
463
 
464
	while (h--)
465
	{
466
		fz_paint_span_with_mask(dp, sp, mp, n, w);
467
		sp += src->w * n;
468
		dp += dst->w * n;
469
		mp += msk->w;
470
	}
471
}