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
/* PDF 1.4 blend modes. These are slow. */
4
 
5
typedef unsigned char byte;
6
 
7
static const char *fz_blendmode_names[] =
8
{
9
	"Normal",
10
	"Multiply",
11
	"Screen",
12
	"Overlay",
13
	"Darken",
14
	"Lighten",
15
	"ColorDodge",
16
	"ColorBurn",
17
	"HardLight",
18
	"SoftLight",
19
	"Difference",
20
	"Exclusion",
21
	"Hue",
22
	"Saturation",
23
	"Color",
24
	"Luminosity",
25
};
26
 
27
int fz_find_blendmode(char *name)
28
{
29
	int i;
30
	for (i = 0; i < nelem(fz_blendmode_names); i++)
31
		if (!strcmp(name, fz_blendmode_names[i]))
32
			return i;
33
	return FZ_BLEND_NORMAL;
34
}
35
 
36
char *fz_blendmode_name(int blendmode)
37
{
38
	if (blendmode >= 0 && blendmode < nelem(fz_blendmode_names))
39
		return (char*)fz_blendmode_names[blendmode];
40
	return "Normal";
41
}
42
 
43
/* Separable blend modes */
44
 
45
static inline int fz_screen_byte(int b, int s)
46
{
47
	return b + s - fz_mul255(b, s);
48
}
49
 
50
static inline int fz_hard_light_byte(int b, int s)
51
{
52
	int s2 = s << 1;
53
	if (s <= 127)
54
		return fz_mul255(b, s2);
55
	else
56
		return fz_screen_byte(b, s2 - 255);
57
}
58
 
59
static inline int fz_overlay_byte(int b, int s)
60
{
61
	return fz_hard_light_byte(s, b); /* note swapped order */
62
}
63
 
64
static inline int fz_darken_byte(int b, int s)
65
{
66
	return MIN(b, s);
67
}
68
 
69
static inline int fz_lighten_byte(int b, int s)
70
{
71
	return MAX(b, s);
72
}
73
 
74
static inline int fz_color_dodge_byte(int b, int s)
75
{
76
	s = 255 - s;
77
	if (b == 0)
78
		return 0;
79
	else if (b >= s)
80
		return 255;
81
	else
82
		return (0x1fe * b + s) / (s << 1);
83
}
84
 
85
static inline int fz_color_burn_byte(int b, int s)
86
{
87
	b = 255 - b;
88
	if (b == 0)
89
		return 255;
90
	else if (b >= s)
91
		return 0;
92
	else
93
		return 0xff - (0x1fe * b + s) / (s << 1);
94
}
95
 
96
static inline int fz_soft_light_byte(int b, int s)
97
{
98
	/* review this */
99
	if (s < 128) {
100
		return b - fz_mul255(fz_mul255((255 - (s<<1)), b), 255 - b);
101
	}
102
	else {
103
		int dbd;
104
		if (b < 64)
105
			dbd = fz_mul255(fz_mul255((b << 4) - 12, b) + 4, b);
106
		else
107
			dbd = (int)sqrtf(255.0f * b);
108
		return b + fz_mul255(((s<<1) - 255), (dbd - b));
109
	}
110
}
111
 
112
static inline int fz_difference_byte(int b, int s)
113
{
114
	return ABS(b - s);
115
}
116
 
117
static inline int fz_exclusion_byte(int b, int s)
118
{
119
	return b + s - (fz_mul255(b, s)<<1);
120
}
121
 
122
/* Non-separable blend modes */
123
 
124
static void
125
fz_luminosity_rgb(int *rd, int *gd, int *bd, int rb, int gb, int bb, int rs, int gs, int bs)
126
{
127
	int delta, scale;
128
	int r, g, b, y;
129
 
130
	/* 0.3, 0.59, 0.11 in fixed point */
131
	delta = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
132
	r = rb + delta;
133
	g = gb + delta;
134
	b = bb + delta;
135
 
136
	if ((r | g | b) & 0x100)
137
	{
138
		y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
139
		if (delta > 0)
140
		{
141
			int max;
142
			max = MAX(r, MAX(g, b));
143
			scale = ((255 - y) << 16) / (max - y);
144
		}
145
		else
146
		{
147
			int min;
148
			min = MIN(r, MIN(g, b));
149
			scale = (y << 16) / (y - min);
150
		}
151
		r = y + (((r - y) * scale + 0x8000) >> 16);
152
		g = y + (((g - y) * scale + 0x8000) >> 16);
153
		b = y + (((b - y) * scale + 0x8000) >> 16);
154
	}
155
 
156
	*rd = r;
157
	*gd = g;
158
	*bd = b;
159
}
160
 
161
static void
162
fz_saturation_rgb(int *rd, int *gd, int *bd, int rb, int gb, int bb, int rs, int gs, int bs)
163
{
164
	int minb, maxb;
165
	int mins, maxs;
166
	int y;
167
	int scale;
168
	int r, g, b;
169
 
170
	minb = MIN(rb, MIN(gb, bb));
171
	maxb = MAX(rb, MAX(gb, bb));
172
	if (minb == maxb)
173
	{
174
		/* backdrop has zero saturation, avoid divide by 0 */
175
		*rd = gb;
176
		*gd = gb;
177
		*bd = gb;
178
		return;
179
	}
180
 
181
	mins = MIN(rs, MIN(gs, bs));
182
	maxs = MAX(rs, MAX(gs, bs));
183
 
184
	scale = ((maxs - mins) << 16) / (maxb - minb);
185
	y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
186
	r = y + ((((rb - y) * scale) + 0x8000) >> 16);
187
	g = y + ((((gb - y) * scale) + 0x8000) >> 16);
188
	b = y + ((((bb - y) * scale) + 0x8000) >> 16);
189
 
190
	if ((r | g | b) & 0x100)
191
	{
192
		int scalemin, scalemax;
193
		int min, max;
194
 
195
		min = MIN(r, MIN(g, b));
196
		max = MAX(r, MAX(g, b));
197
 
198
		if (min < 0)
199
			scalemin = (y << 16) / (y - min);
200
		else
201
			scalemin = 0x10000;
202
 
203
		if (max > 255)
204
			scalemax = ((255 - y) << 16) / (max - y);
205
		else
206
			scalemax = 0x10000;
207
 
208
		scale = MIN(scalemin, scalemax);
209
		r = y + (((r - y) * scale + 0x8000) >> 16);
210
		g = y + (((g - y) * scale + 0x8000) >> 16);
211
		b = y + (((b - y) * scale + 0x8000) >> 16);
212
	}
213
 
214
	*rd = r;
215
	*gd = g;
216
	*bd = b;
217
}
218
 
219
static void
220
fz_color_rgb(int *rr, int *rg, int *rb, int br, int bg, int bb, int sr, int sg, int sb)
221
{
222
	fz_luminosity_rgb(rr, rg, rb, sr, sg, sb, br, bg, bb);
223
}
224
 
225
static void
226
fz_hue_rgb(int *rr, int *rg, int *rb, int br, int bg, int bb, int sr, int sg, int sb)
227
{
228
	int tr, tg, tb;
229
	fz_luminosity_rgb(&tr, &tg, &tb, sr, sg, sb, br, bg, bb);
230
	fz_saturation_rgb(rr, rg, rb, tr, tg, tb, br, bg, bb);
231
}
232
 
233
/* Blending loops */
234
 
235
void
236
fz_blend_separable(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode)
237
{
238
	int k;
239
	int n1 = n - 1;
240
	while (w--)
241
	{
242
		int sa = sp[n1];
243
		int ba = bp[n1];
244
		int saba = fz_mul255(sa, ba);
245
 
246
		/* ugh, division to get non-premul components */
247
		int invsa = sa ? 255 * 256 / sa : 0;
248
		int invba = ba ? 255 * 256 / ba : 0;
249
 
250
		for (k = 0; k < n1; k++)
251
		{
252
			int sc = (sp[k] * invsa) >> 8;
253
			int bc = (bp[k] * invba) >> 8;
254
			int rc;
255
 
256
			switch (blendmode)
257
			{
258
			default:
259
			case FZ_BLEND_NORMAL: rc = sc; break;
260
			case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
261
			case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
262
			case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
263
			case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
264
			case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
265
			case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
266
			case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
267
			case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
268
			case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
269
			case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
270
			case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
271
			}
272
 
273
			bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, rc);
274
		}
275
 
276
		bp[k] = ba + sa - saba;
277
 
278
		sp += n;
279
		bp += n;
280
	}
281
}
282
 
283
void
284
fz_blend_nonseparable(byte * restrict bp, byte * restrict sp, int w, int blendmode)
285
{
286
	while (w--)
287
	{
288
		int rr, rg, rb;
289
 
290
		int sa = sp[3];
291
		int ba = bp[3];
292
		int saba = fz_mul255(sa, ba);
293
 
294
		/* ugh, division to get non-premul components */
295
		int invsa = sa ? 255 * 256 / sa : 0;
296
		int invba = ba ? 255 * 256 / ba : 0;
297
 
298
		int sr = (sp[0] * invsa) >> 8;
299
		int sg = (sp[1] * invsa) >> 8;
300
		int sb = (sp[2] * invsa) >> 8;
301
 
302
		int br = (bp[0] * invba) >> 8;
303
		int bg = (bp[1] * invba) >> 8;
304
		int bb = (bp[2] * invba) >> 8;
305
 
306
		switch (blendmode)
307
		{
308
		default:
309
		case FZ_BLEND_HUE:
310
			fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
311
			break;
312
		case FZ_BLEND_SATURATION:
313
			fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
314
			break;
315
		case FZ_BLEND_COLOR:
316
			fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
317
			break;
318
		case FZ_BLEND_LUMINOSITY:
319
			fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
320
			break;
321
		}
322
 
323
		bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr);
324
		bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg);
325
		bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb);
326
		bp[3] = ba + sa - saba;
327
 
328
		sp += 4;
329
		bp += 4;
330
	}
331
}
332
 
333
static void
334
fz_blend_separable_nonisolated(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode, byte * restrict hp, int alpha)
335
{
336
	int k;
337
	int n1 = n - 1;
338
 
339
	if (alpha == 255 && blendmode == 0)
340
	{
341
		/* In this case, the uncompositing and the recompositing
342
		 * cancel one another out, and it's just a simple copy. */
343
		/* FIXME: Maybe we can avoid using the shape plane entirely
344
		 * and just copy? */
345
		while (w--)
346
		{
347
			int ha = fz_mul255(*hp++, alpha); /* ha = shape_alpha */
348
			/* If ha == 0 then leave everything unchanged */
349
			if (ha != 0)
350
			{
351
				for (k = 0; k < n; k++)
352
				{
353
					bp[k] = sp[k];
354
				}
355
			}
356
 
357
			sp += n;
358
			bp += n;
359
		}
360
		return;
361
	}
362
	while (w--)
363
	{
364
		int ha = *hp++;
365
		int haa = fz_mul255(ha, alpha); /* ha = shape_alpha */
366
		/* If haa == 0 then leave everything unchanged */
367
		if (haa != 0)
368
		{
369
			int sa = sp[n1];
370
			int ba = bp[n1];
371
			int baha = fz_mul255(ba, haa);
372
 
373
			/* ugh, division to get non-premul components */
374
			int invsa = sa ? 255 * 256 / sa : 0;
375
			int invba = ba ? 255 * 256 / ba : 0;
376
 
377
			/* Calculate result_alpha */
378
			int ra = bp[n1] = ba - baha + haa;
379
 
380
			/* Because we are a non-isolated group, we need to
381
			 * 'uncomposite' before we blend (recomposite).
382
			 * We assume that normal blending has been done inside
383
			 * the group, so:   ra.rc = (1-ha).bc + ha.sc
384
			 * A bit of rearrangement, and that gives us that:
385
			 *  sc = (ra.rc - bc)/ha + bc
386
			 * Now, the result of the blend was stored in src, so:
387
			 */
388
			int invha = ha ? 255 * 256 / ha : 0;
389
 
390
			if (ra != 0) for (k = 0; k < n1; k++)
391
			{
392
				int sc = (sp[k] * invsa) >> 8;
393
				int bc = (bp[k] * invba) >> 8;
394
				int rc;
395
 
396
				/* Uncomposite */
397
				sc = (((sc-bc)*invha)>>8) + bc;
398
				if (sc < 0) sc = 0;
399
				if (sc > 255) sc = 255;
400
 
401
				switch (blendmode)
402
				{
403
				default:
404
				case FZ_BLEND_NORMAL: rc = sc; break;
405
				case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
406
				case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
407
				case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
408
				case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
409
				case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
410
				case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
411
				case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
412
				case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
413
				case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
414
				case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
415
				case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
416
				}
417
				rc = fz_mul255(255 - haa, bc) + fz_mul255(fz_mul255(255 - ba, sc), haa) + fz_mul255(baha, rc);
418
				if (rc < 0) rc = 0;
419
				if (rc > 255) rc = 255;
420
				bp[k] = fz_mul255(rc, ra);
421
			}
422
		}
423
 
424
		sp += n;
425
		bp += n;
426
	}
427
}
428
 
429
static void
430
fz_blend_nonseparable_nonisolated(byte * restrict bp, byte * restrict sp, int w, int blendmode, byte * restrict hp, int alpha)
431
{
432
	while (w--)
433
	{
434
		int ha = *hp++;
435
		int haa = fz_mul255(ha, alpha);
436
		if (haa != 0)
437
		{
438
			int sa = sp[3];
439
			int ba = bp[3];
440
			int baha = fz_mul255(ba, haa);
441
 
442
			/* Calculate result_alpha */
443
			int ra = bp[3] = ba - baha + haa;
444
			if (ra != 0)
445
			{
446
				/* Because we are a non-isolated group, we
447
				 * need to 'uncomposite' before we blend
448
				 * (recomposite). We assume that normal
449
				 * blending has been done inside the group,
450
				 * so:     ra.rc = (1-ha).bc + ha.sc
451
				 * A bit of rearrangement, and that gives us
452
				 * that:   sc = (ra.rc - bc)/ha + bc
453
				 * Now, the result of the blend was stored in
454
				 * src, so: */
455
				int invha = ha ? 255 * 256 / ha : 0;
456
 
457
				int rr, rg, rb;
458
 
459
				/* ugh, division to get non-premul components */
460
				int invsa = sa ? 255 * 256 / sa : 0;
461
				int invba = ba ? 255 * 256 / ba : 0;
462
 
463
				int sr = (sp[0] * invsa) >> 8;
464
				int sg = (sp[1] * invsa) >> 8;
465
				int sb = (sp[2] * invsa) >> 8;
466
 
467
				int br = (bp[0] * invba) >> 8;
468
				int bg = (bp[1] * invba) >> 8;
469
				int bb = (bp[2] * invba) >> 8;
470
 
471
				/* Uncomposite */
472
				sr = (((sr-br)*invha)>>8) + br;
473
				sg = (((sg-bg)*invha)>>8) + bg;
474
				sb = (((sb-bb)*invha)>>8) + bb;
475
 
476
				switch (blendmode)
477
				{
478
				default:
479
				case FZ_BLEND_HUE:
480
					fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
481
					break;
482
				case FZ_BLEND_SATURATION:
483
					fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
484
					break;
485
				case FZ_BLEND_COLOR:
486
					fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
487
					break;
488
				case FZ_BLEND_LUMINOSITY:
489
					fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
490
					break;
491
				}
492
 
493
				rr = fz_mul255(255 - haa, bp[0]) + fz_mul255(fz_mul255(255 - ba, sr), haa) + fz_mul255(baha, rr);
494
				rg = fz_mul255(255 - haa, bp[1]) + fz_mul255(fz_mul255(255 - ba, sg), haa) + fz_mul255(baha, rg);
495
				rb = fz_mul255(255 - haa, bp[2]) + fz_mul255(fz_mul255(255 - ba, sb), haa) + fz_mul255(baha, rb);
496
				bp[0] = fz_mul255(ra, rr);
497
				bp[1] = fz_mul255(ra, rg);
498
				bp[2] = fz_mul255(ra, rb);
499
			}
500
		}
501
 
502
		sp += 4;
503
		bp += 4;
504
	}
505
}
506
 
507
void
508
fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape)
509
{
510
	unsigned char *sp, *dp;
511
	fz_bbox bbox;
512
	int x, y, w, h, n;
513
 
514
	/* TODO: fix this hack! */
515
	if (isolated && alpha < 255)
516
	{
517
		sp = src->samples;
518
		n = src->w * src->h * src->n;
519
		while (n--)
520
		{
521
			*sp = fz_mul255(*sp, alpha);
522
			sp++;
523
		}
524
	}
525
 
526
	bbox = fz_bound_pixmap(dst);
527
	bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src));
528
 
529
	x = bbox.x0;
530
	y = bbox.y0;
531
	w = bbox.x1 - bbox.x0;
532
	h = bbox.y1 - bbox.y0;
533
 
534
	n = src->n;
535
	sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * n;
536
	dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * n;
537
 
538
	assert(src->n == dst->n);
539
 
540
	if (!isolated)
541
	{
542
		unsigned char *hp = shape->samples + (y - shape->y) * shape->w + (x - shape->x);
543
 
544
		while (h--)
545
		{
546
			if (n == 4 && blendmode >= FZ_BLEND_HUE)
547
				fz_blend_nonseparable_nonisolated(dp, sp, w, blendmode, hp, alpha);
548
			else
549
				fz_blend_separable_nonisolated(dp, sp, n, w, blendmode, hp, alpha);
550
			sp += src->w * n;
551
			dp += dst->w * n;
552
			hp += shape->w;
553
		}
554
	}
555
	else
556
	{
557
		while (h--)
558
		{
559
			if (n == 4 && blendmode >= FZ_BLEND_HUE)
560
				fz_blend_nonseparable(dp, sp, w, blendmode);
561
			else
562
				fz_blend_separable(dp, sp, n, w, blendmode);
563
			sp += src->w * n;
564
			dp += dst->w * n;
565
		}
566
	}
567
}