xref: /plan9/sys/src/cmd/gs/src/gxblend.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /*
2   Copyright (C) 2001 artofcode LLC.
3 
4   This software is provided AS-IS with no warranty, either express or
5   implied.
6 
7   This software is distributed under license and may not be copied,
8   modified or distributed except as expressly authorized under the terms
9   of the license contained in the file LICENSE in this distribution.
10 
11   For more information about licensing, please refer to
12   http://www.ghostscript.com/licensing/. For information on
13   commercial licensing, go to http://www.artifex.com/licensing/ or
14   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
15   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
16 
17   Author: Raph Levien <raph@artofcode.com>
18 */
19 /* $Id: gxblend.c,v 1.6 2004/08/18 04:48:56 dan Exp $ */
20 /* PDF 1.4 blending functions */
21 
22 #include "memory_.h"
23 #include "gx.h"
24 #include "gstparam.h"
25 #include "gxblend.h"
26 
27 typedef int art_s32;
28 
29 static void
art_blend_luminosity_rgb_8(byte * dst,const byte * backdrop,const byte * src)30 art_blend_luminosity_rgb_8(byte *dst, const byte *backdrop,
31 			   const byte *src)
32 {
33     int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
34     int rs = src[0], gs = src[1], bs = src[2];
35     int delta_y;
36     int r, g, b;
37 
38     /*
39      * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
40      * is:  Y = 0.30 R + 0.59 G + 0.11 B)
41      */
42     delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
43     r = rb + delta_y;
44     g = gb + delta_y;
45     b = bb + delta_y;
46     if ((r | g | b) & 0x100) {
47 	int y;
48 	int scale;
49 
50 	y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
51 	if (delta_y > 0) {
52 	    int max;
53 
54 	    max = r > g ? r : g;
55 	    max = b > max ? b : max;
56 	    scale = ((255 - y) << 16) / (max - y);
57 	} else {
58 	    int min;
59 
60 	    min = r < g ? r : g;
61 	    min = b < min ? b : min;
62 	    scale = (y << 16) / (y - min);
63 	}
64 	r = y + (((r - y) * scale + 0x8000) >> 16);
65 	g = y + (((g - y) * scale + 0x8000) >> 16);
66 	b = y + (((b - y) * scale + 0x8000) >> 16);
67     }
68     dst[0] = r;
69     dst[1] = g;
70     dst[2] = b;
71 }
72 
73 /*
74  * The PDF 1.4 spec. does not give the details of the math involved in the
75  * luminosity blending.  All we are given is:
76  *   "Creates a color with the luminance of the source color and the hue
77  *    and saturation of the backdrop color. This produces an inverse
78  *    effect to that of the Color mode."
79  * From section 7.4 of the PDF 1.5 specification, which is duscussing soft
80  * masks, we are given that, for CMYK, the luminosity is:
81  *    Y = 0.30 (1 - C)(1 - K) + 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K)
82  * However the results of this equation do not match the results seen from
83  * Illustrator CS.  Very different results are obtained if process gray
84  * (.5, .5, .5, 0) is blended over pure cyan, versus gray (0, 0, 0, .5) over
85  * the same pure cyan.  The first gives a medium cyan while the later gives a
86  * medium gray.  This routine seems to match Illustrator's actions.  C, M and Y
87  * are treated similar to RGB in the previous routine and black is treated
88  * separately.
89  *
90  * Our component values have already been complemented, i.e. (1 - X).
91  */
92 static void
art_blend_luminosity_cmyk_8(byte * dst,const byte * backdrop,const byte * src)93 art_blend_luminosity_cmyk_8(byte *dst, const byte *backdrop,
94 			   const byte *src)
95 {
96     /* Treat CMY the same as RGB. */
97     art_blend_luminosity_rgb_8(dst, backdrop, src);
98     dst[3] = src[3];
99 }
100 
101 static void
art_blend_saturation_rgb_8(byte * dst,const byte * backdrop,const byte * src)102 art_blend_saturation_rgb_8(byte *dst, const byte *backdrop,
103 			   const byte *src)
104 {
105     int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
106     int rs = src[0], gs = src[1], bs = src[2];
107     int minb, maxb;
108     int mins, maxs;
109     int y;
110     int scale;
111     int r, g, b;
112 
113     minb = rb < gb ? rb : gb;
114     minb = minb < bb ? minb : bb;
115     maxb = rb > gb ? rb : gb;
116     maxb = maxb > bb ? maxb : bb;
117     if (minb == maxb) {
118 	/* backdrop has zero saturation, avoid divide by 0 */
119 	dst[0] = gb;
120 	dst[1] = gb;
121 	dst[2] = gb;
122 	return;
123     }
124 
125     mins = rs < gs ? rs : gs;
126     mins = mins < bs ? mins : bs;
127     maxs = rs > gs ? rs : gs;
128     maxs = maxs > bs ? maxs : bs;
129 
130     scale = ((maxs - mins) << 16) / (maxb - minb);
131     y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
132     r = y + ((((rb - y) * scale) + 0x8000) >> 16);
133     g = y + ((((gb - y) * scale) + 0x8000) >> 16);
134     b = y + ((((bb - y) * scale) + 0x8000) >> 16);
135 
136     if ((r | g | b) & 0x100) {
137 	int scalemin, scalemax;
138 	int min, max;
139 
140 	min = r < g ? r : g;
141 	min = min < b ? min : b;
142 	max = r > g ? r : g;
143 	max = max > b ? max : b;
144 
145 	if (min < 0)
146 	    scalemin = (y << 16) / (y - min);
147 	else
148 	    scalemin = 0x10000;
149 
150 	if (max > 255)
151 	    scalemax = ((255 - y) << 16) / (max - y);
152 	else
153 	    scalemax = 0x10000;
154 
155 	scale = scalemin < scalemax ? scalemin : scalemax;
156 	r = y + (((r - y) * scale + 0x8000) >> 16);
157 	g = y + (((g - y) * scale + 0x8000) >> 16);
158 	b = y + (((b - y) * scale + 0x8000) >> 16);
159     }
160 
161     dst[0] = r;
162     dst[1] = g;
163     dst[2] = b;
164 }
165 
166 /* Our component values have already been complemented, i.e. (1 - X). */
167 static void
art_blend_saturation_cmyk_8(byte * dst,const byte * backdrop,const byte * src)168 art_blend_saturation_cmyk_8(byte *dst, const byte *backdrop,
169 			   const byte *src)
170 {
171     /* Treat CMY the same as RGB */
172     art_blend_saturation_rgb_8(dst, backdrop, src);
173     dst[3] = backdrop[3];
174 }
175 
176 /* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 +
177    0.5) for x in [0..255]. */
178 const unsigned int art_blend_sq_diff_8[256] = {
179     0, 256, 510, 762, 1012, 1260, 1506, 1750, 1992, 2231, 2469, 2705,
180     2939, 3171, 3401, 3628, 3854, 4078, 4300, 4519, 4737, 4953, 5166,
181     5378, 5588, 5795, 6001, 6204, 6406, 6606, 6803, 6999, 7192, 7384,
182     7573, 7761, 7946, 8129, 8311, 8490, 8668, 8843, 9016, 9188, 9357,
183     9524, 9690, 9853, 10014, 10173, 10331, 10486, 10639, 10790, 10939,
184     11086, 11232, 11375, 11516, 11655, 11792, 11927, 12060, 12191, 12320,
185     12447, 12572, 12695, 12816, 12935, 13052, 13167, 13280, 13390, 13499,
186     13606, 13711, 13814, 13914, 14013, 14110, 14205, 14297, 14388, 14477,
187     14564, 14648, 14731, 14811, 14890, 14967, 15041, 15114, 15184, 15253,
188     15319, 15384, 15446, 15507, 15565, 15622, 15676, 15729, 15779, 15827,
189     15874, 15918, 15960, 16001, 16039, 16075, 16110, 16142, 16172, 16200,
190     16227, 16251, 16273, 16293, 16311, 16327, 16341, 16354, 16364, 16372,
191     16378, 16382, 16384, 16384, 16382, 16378, 16372, 16364, 16354, 16341,
192     16327, 16311, 16293, 16273, 16251, 16227, 16200, 16172, 16142, 16110,
193     16075, 16039, 16001, 15960, 15918, 15874, 15827, 15779, 15729, 15676,
194     15622, 15565, 15507, 15446, 15384, 15319, 15253, 15184, 15114, 15041,
195     14967, 14890, 14811, 14731, 14648, 14564, 14477, 14388, 14297, 14205,
196     14110, 14013, 13914, 13814, 13711, 13606, 13499, 13390, 13280, 13167,
197     13052, 12935, 12816, 12695, 12572, 12447, 12320, 12191, 12060, 11927,
198     11792, 11655, 11516, 11375, 11232, 11086, 10939, 10790, 10639, 10486,
199     10331, 10173, 10014, 9853, 9690, 9524, 9357, 9188, 9016, 8843, 8668,
200     8490, 8311, 8129, 7946, 7761, 7573, 7384, 7192, 6999, 6803, 6606,
201     6406, 6204, 6001, 5795, 5588, 5378, 5166, 4953, 4737, 4519, 4300,
202     4078, 3854, 3628, 3401, 3171, 2939, 2705, 2469, 2231, 1992, 1750,
203     1506, 1260, 1012, 762, 510, 256, 0
204 };
205 
206 /* This array consists of SoftLight (x, 255) - x, for values of x in
207    the range [0..255] (normalized to [0..255 range). The original
208    values were directly sampled from Adobe Illustrator 9. I've fit a
209    quadratic spline to the SoftLight (x, 1) function as follows
210    (normalized to [0..1] range):
211 
212    Anchor point (0, 0)
213    Control point (0.0755, 0.302)
214    Anchor point (0.18, 0.4245)
215    Control point (0.4263, 0.7131)
216    Anchor point (1, 1)
217 
218    I don't believe this is _exactly_ the function that Adobe uses,
219    but it really should be close enough for all practical purposes.  */
220 const byte art_blend_soft_light_8[256] = {
221     0, 3, 6, 9, 11, 14, 16, 19, 21, 23, 26, 28, 30, 32, 33, 35, 37, 39,
222     40, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 53, 54, 55, 56, 57, 57,
223     58, 58, 59, 60, 60, 60, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 63,
224     63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
225     64, 64, 64, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62,
226     62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 59, 59,
227     59, 59, 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55,
228     55, 55, 54, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 51, 50,
229     50, 50, 49, 49, 49, 48, 48, 48, 47, 47, 47, 46, 46, 46, 45, 45, 45,
230     44, 44, 43, 43, 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 39, 38,
231     38, 37, 37, 37, 36, 36, 35, 35, 35, 34, 34, 33, 33, 33, 32, 32, 31,
232     31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 25, 25, 25, 24,
233     24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
234     16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7,
235     7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0
236 };
237 
238 void
art_blend_pixel_8(byte * dst,const byte * backdrop,const byte * src,int n_chan,gs_blend_mode_t blend_mode)239 art_blend_pixel_8(byte *dst, const byte *backdrop,
240 		  const byte *src, int n_chan, gs_blend_mode_t blend_mode)
241 {
242     int i;
243     byte b, s;
244     bits32 t;
245 
246     switch (blend_mode) {
247 	case BLEND_MODE_Normal:
248 	case BLEND_MODE_Compatible:	/* todo */
249 	    memcpy(dst, src, n_chan);
250 	    break;
251 	case BLEND_MODE_Multiply:
252 	    for (i = 0; i < n_chan; i++) {
253 		t = ((bits32) backdrop[i]) * ((bits32) src[i]);
254 		t += 0x80;
255 		t += (t >> 8);
256 		dst[i] = t >> 8;
257 	    }
258 	    break;
259 	case BLEND_MODE_Screen:
260 	    for (i = 0; i < n_chan; i++) {
261 		t =
262 		    ((bits32) (0xff - backdrop[i])) *
263 		    ((bits32) (0xff - src[i]));
264 		t += 0x80;
265 		t += (t >> 8);
266 		dst[i] = 0xff - (t >> 8);
267 	    }
268 	    break;
269 	case BLEND_MODE_Overlay:
270 	    for (i = 0; i < n_chan; i++) {
271 		b = backdrop[i];
272 		s = src[i];
273 		if (b < 0x80)
274 		    t = 2 * ((bits32) b) * ((bits32) s);
275 		else
276 		    t = 0xfe01 -
277 			2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
278 		t += 0x80;
279 		t += (t >> 8);
280 		dst[i] = t >> 8;
281 	    }
282 	    break;
283 	case BLEND_MODE_SoftLight:
284 	    for (i = 0; i < n_chan; i++) {
285 		b = backdrop[i];
286 		s = src[i];
287 		if (s < 0x80) {
288 		    t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
289 		    t += 0x8000;
290 		    dst[i] = b - (t >> 16);
291 		} else {
292 		    t =
293 			((s << 1) -
294 			 0xff) * ((bits32) (art_blend_soft_light_8[b]));
295 		    t += 0x80;
296 		    t += (t >> 8);
297 		    dst[i] = b + (t >> 8);
298 		}
299 	    }
300 	    break;
301 	case BLEND_MODE_HardLight:
302 	    for (i = 0; i < n_chan; i++) {
303 		b = backdrop[i];
304 		s = src[i];
305 		if (s < 0x80)
306 		    t = 2 * ((bits32) b) * ((bits32) s);
307 		else
308 		    t = 0xfe01 -
309 			2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
310 		t += 0x80;
311 		t += (t >> 8);
312 		dst[i] = t >> 8;
313 	    }
314 	    break;
315 	case BLEND_MODE_ColorDodge:
316 	    for (i = 0; i < n_chan; i++) {
317 		b = backdrop[i];
318 		s = 0xff - src[i];
319 		if (b == 0)
320 		    dst[i] = 0;
321 		else if (b >= s)
322 		    dst[i] = 0xff;
323 		else
324 		    dst[i] = (0x1fe * b + s) / (s << 1);
325 	    }
326 	    break;
327 	case BLEND_MODE_ColorBurn:
328 	    for (i = 0; i < n_chan; i++) {
329 		b = 0xff - backdrop[i];
330 		s = src[i];
331 		if (b == 0)
332 		    dst[i] = 0xff;
333 		else if (b >= s)
334 		    dst[i] = 0;
335 		else
336 		    dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
337 	    }
338 	    break;
339 	case BLEND_MODE_Darken:
340 	    for (i = 0; i < n_chan; i++) {
341 		b = backdrop[i];
342 		s = src[i];
343 		dst[i] = b < s ? b : s;
344 	    }
345 	    break;
346 	case BLEND_MODE_Lighten:
347 	    for (i = 0; i < n_chan; i++) {
348 		b = backdrop[i];
349 		s = src[i];
350 		dst[i] = b > s ? b : s;
351 	    }
352 	    break;
353 	case BLEND_MODE_Difference:
354 	    for (i = 0; i < n_chan; i++) {
355 		art_s32 tmp;
356 
357 		tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
358 		dst[i] = tmp < 0 ? -tmp : tmp;
359 	    }
360 	    break;
361 	case BLEND_MODE_Exclusion:
362 	    for (i = 0; i < n_chan; i++) {
363 		b = backdrop[i];
364 		s = src[i];
365 		t = ((bits32) (0xff - b)) * ((bits32) s) +
366 		    ((bits32) b) * ((bits32) (0xff - s));
367 		t += 0x80;
368 		t += (t >> 8);
369 		dst[i] = t >> 8;
370 	    }
371 	    break;
372 	case BLEND_MODE_Luminosity:
373 	    switch (n_chan) {
374 		case 1:			/* DeviceGray */
375 	    	    dlprintf(
376 			"art_blend_pixel_8: DeviceGray luminosity blend mode not implemented\n");
377 		    break;
378 		case 3:			/* DeviceRGB */
379 	    	    art_blend_luminosity_rgb_8(dst, backdrop, src);
380 		    break;
381 		case 4:			/* DeviceCMYK */
382 	    	    art_blend_luminosity_cmyk_8(dst, backdrop, src);
383 		    break;
384 		default:		/* Should not happen */
385 		    break;
386 	    }
387 	    break;
388 	case BLEND_MODE_Color:
389 	    switch (n_chan) {
390 		case 1:			/* DeviceGray */
391 	    	    dlprintf(
392 			"art_blend_pixel_8: DeviceGray color blend mode not implemented\n");
393 		    break;
394 		case 3:			/* DeviceRGB */
395 		    art_blend_luminosity_rgb_8(dst, src, backdrop);
396 		    break;
397 		case 4:			/* DeviceCMYK */
398 		    art_blend_luminosity_cmyk_8(dst, src, backdrop);
399 		    break;
400 		default:		/* Should not happen */
401 		    break;
402 	    }
403 	    break;
404 	case BLEND_MODE_Saturation:
405 	    switch (n_chan) {
406 		case 1:			/* DeviceGray */
407 	    	    dlprintf(
408 			"art_blend_pixel_8: DeviceGray saturation blend mode not implemented\n");
409 		    break;
410 		case 3:			/* DeviceRGB */
411 	    	    art_blend_saturation_rgb_8(dst, backdrop, src);
412 		    break;
413 		case 4:			/* DeviceCMYK */
414 	    	    art_blend_saturation_cmyk_8(dst, backdrop, src);
415 		    break;
416 		default:		/* Should not happen */
417 		    break;
418 	    }
419 	    break;
420 	case BLEND_MODE_Hue:
421 	    {
422 		byte tmp[4];
423 
424 	        switch (n_chan) {
425 		    case 1:		/* DeviceGray */
426 	    		dlprintf(
427 			    "art_blend_pixel_8: DeviceGray hue blend mode not implemented\n");
428 		        break;
429 		    case 3:		/* DeviceRGB */
430 			art_blend_luminosity_rgb_8(tmp, src, backdrop);
431 			art_blend_saturation_rgb_8(dst, tmp, backdrop);
432 		        break;
433 		    case 4:		/* DeviceCMYK */
434 		        art_blend_luminosity_cmyk_8(tmp, src, backdrop);
435 			art_blend_saturation_cmyk_8(dst, tmp, backdrop);
436 		        break;
437 		    default:		/* Should not happen */
438 		        break;
439 	        }
440 	    }
441 	    break;
442 	default:
443 	    dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
444 		      blend_mode);
445 	    memcpy(dst, src, n_chan);
446 	    break;
447     }
448 }
449 
450 void
art_blend_pixel(ArtPixMaxDepth * dst,const ArtPixMaxDepth * backdrop,const ArtPixMaxDepth * src,int n_chan,gs_blend_mode_t blend_mode)451 art_blend_pixel(ArtPixMaxDepth* dst, const ArtPixMaxDepth *backdrop,
452 		const ArtPixMaxDepth* src, int n_chan,
453 		gs_blend_mode_t blend_mode)
454 {
455     int i;
456     ArtPixMaxDepth b, s;
457     bits32 t;
458 
459     switch (blend_mode) {
460 	case BLEND_MODE_Normal:
461 	case BLEND_MODE_Compatible:	/* todo */
462 	    memcpy(dst, src, n_chan * sizeof(ArtPixMaxDepth));
463 	    break;
464 	case BLEND_MODE_Multiply:
465 	    for (i = 0; i < n_chan; i++) {
466 		t = ((bits32) backdrop[i]) * ((bits32) src[i]);
467 		t += 0x8000;
468 		t += (t >> 16);
469 		dst[i] = t >> 16;
470 	    }
471 	    break;
472 	case BLEND_MODE_Screen:
473 	    for (i = 0; i < n_chan; i++) {
474 		t =
475 		    ((bits32) (0xffff - backdrop[i])) *
476 		    ((bits32) (0xffff - src[i]));
477 		t += 0x8000;
478 		t += (t >> 16);
479 		dst[i] = 0xffff - (t >> 16);
480 	    }
481 	    break;
482 	case BLEND_MODE_Overlay:
483 	    for (i = 0; i < n_chan; i++) {
484 		b = backdrop[i];
485 		s = src[i];
486 		if (b < 0x8000)
487 		    t = 2 * ((bits32) b) * ((bits32) s);
488 		else
489 		    t = 0xfffe0001u -
490 			2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
491 		t += 0x8000;
492 		t += (t >> 16);
493 		dst[i] = t >> 16;
494 	    }
495 	    break;
496 	case BLEND_MODE_HardLight:
497 	    for (i = 0; i < n_chan; i++) {
498 		b = backdrop[i];
499 		s = src[i];
500 		if (s < 0x8000)
501 		    t = 2 * ((bits32) b) * ((bits32) s);
502 		else
503 		    t = 0xfffe0001u -
504 			2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
505 		t += 0x8000;
506 		t += (t >> 16);
507 		dst[i] = t >> 16;
508 	    }
509 	    break;
510 	case BLEND_MODE_ColorDodge:
511 	    for (i = 0; i < n_chan; i++) {
512 		b = backdrop[i];
513 		s = src[i];
514 		if (b == 0)
515 		    dst[i] = 0;
516 		else if (s >= b)
517 		    dst[i] = 0xffff;
518 		else
519 		    dst[i] = (0x1fffe * s + b) / (b << 1);
520 	    }
521 	    break;
522 	case BLEND_MODE_ColorBurn:
523 	    for (i = 0; i < n_chan; i++) {
524 		b = 0xffff - backdrop[i];
525 		s = src[i];
526 		if (b == 0)
527 		    dst[i] = 0xffff;
528 		else if (b >= s)
529 		    dst[i] = 0;
530 		else
531 		    dst[i] = 0xffff - (0x1fffe * b + s) / (s << 1);
532 	    }
533 	case BLEND_MODE_Darken:
534 	    for (i = 0; i < n_chan; i++) {
535 		b = backdrop[i];
536 		s = src[i];
537 		dst[i] = b < s ? b : s;
538 	    }
539 	    break;
540 	case BLEND_MODE_Lighten:
541 	    for (i = 0; i < n_chan; i++) {
542 		b = backdrop[i];
543 		s = src[i];
544 		dst[i] = b > s ? b : s;
545 	    }
546 	    break;
547 	case BLEND_MODE_Difference:
548 	    for (i = 0; i < n_chan; i++) {
549 		art_s32 tmp;
550 
551 		tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
552 		dst[i] = tmp < 0 ? -tmp : tmp;
553 	    }
554 	    break;
555 	case BLEND_MODE_Exclusion:
556 	    for (i = 0; i < n_chan; i++) {
557 		b = backdrop[i];
558 		s = src[i];
559 		t = ((bits32) (0xffff - b)) * ((bits32) s) +
560 		    ((bits32) b) * ((bits32) (0xffff - s));
561 		t += 0x8000;
562 		t += (t >> 16);
563 		dst[i] = t >> 16;
564 	    }
565 	    break;
566 	default:
567 	    dlprintf1("art_blend_pixel: blend mode %d not implemented\n",
568 		      blend_mode);
569 	    memcpy(dst, src, n_chan);
570 	    break;
571     }
572 }
573 
574 byte
art_pdf_union_8(byte alpha1,byte alpha2)575 art_pdf_union_8(byte alpha1, byte alpha2)
576 {
577     int tmp;
578 
579     tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
580     return 0xff - ((tmp + (tmp >> 8)) >> 8);
581 }
582 
583 byte
art_pdf_union_mul_8(byte alpha1,byte alpha2,byte alpha_mask)584 art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask)
585 {
586     int tmp;
587 
588     if (alpha_mask == 0xff) {
589 	tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
590 	return 0xff - ((tmp + (tmp >> 8)) >> 8);
591     } else {
592 	tmp = alpha2 * alpha_mask + 0x80;
593 	tmp = (tmp + (tmp >> 8)) >> 8;
594 	tmp = (0xff - alpha1) * (0xff - tmp) + 0x80;
595 	return 0xff - ((tmp + (tmp >> 8)) >> 8);
596     }
597 }
598 
599 void
art_pdf_composite_pixel_alpha_8(byte * dst,const byte * src,int n_chan,gs_blend_mode_t blend_mode)600 art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan,
601 				gs_blend_mode_t blend_mode)
602 {
603     byte a_b, a_s;
604     unsigned int a_r;
605     int tmp;
606     int src_scale;
607     int c_b, c_s;
608     int i;
609 
610     a_s = src[n_chan];
611     if (a_s == 0) {
612 	/* source alpha is zero, avoid all computations and possible
613 	   divide by zero errors. */
614 	return;
615     }
616 
617     a_b = dst[n_chan];
618     if (a_b == 0) {
619 	/* backdrop alpha is zero, just copy source pixels and avoid
620 	   computation. */
621 
622 	/* this idiom is faster than memcpy (dst, src, n_chan + 1); for
623 	   expected small values of n_chan. */
624 	for (i = 0; i <= n_chan >> 2; i++) {
625 	    ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
626 	}
627 
628 	return;
629     }
630 
631     /* Result alpha is Union of backdrop and source alpha */
632     tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
633     a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
634     /* todo: verify that a_r is nonzero in all cases */
635 
636     /* Compute a_s / a_r in 16.16 format */
637     src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
638 
639     if (blend_mode == BLEND_MODE_Normal) {
640 	/* Do simple compositing of source over backdrop */
641 	for (i = 0; i < n_chan; i++) {
642 	    c_s = src[i];
643 	    c_b = dst[i];
644 	    tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
645 	    dst[i] = tmp >> 16;
646 	}
647     } else {
648 	/* Do compositing with blending */
649 	byte blend[ART_MAX_CHAN];
650 
651 	art_blend_pixel_8(blend, dst, src, n_chan, blend_mode);
652 	for (i = 0; i < n_chan; i++) {
653 	    int c_bl;		/* Result of blend function */
654 	    int c_mix;		/* Blend result mixed with source color */
655 
656 	    c_s = src[i];
657 	    c_b = dst[i];
658 	    c_bl = blend[i];
659 	    tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
660 	    c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
661 	    tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
662 	    dst[i] = tmp >> 16;
663 	}
664     }
665     dst[n_chan] = a_r;
666 }
667 
668 #if 0
669 /**
670  * art_pdf_composite_pixel_knockout_8: Composite two pixels with knockout.
671  * @dst: Where to store resulting pixel, also immediate backdrop.
672  * @backdrop: Initial backdrop color.
673  * @src: Source pixel color.
674  * @n_chan: Number of channels.
675  * @blend_mode: Blend mode.
676  *
677  * Composites two pixels using the compositing operation specialized
678  * for knockout groups (Section 5.5). A few things to keep in mind:
679  *
680  * 1. This is a reference implementation, not a high-performance one.
681  *
682  * 2. All pixels are assumed to have a single alpha channel.
683  *
684  * 3. Zero is black, one is white.
685  *
686  * Also note that src and dst are expected to be allocated aligned to
687  * 32 bit boundaries, ie bytes from [0] to [(n_chan + 3) & -4] may
688  * be accessed.
689  *
690  * All pixel values have both alpha and shape channels, ie with those
691  * included the total number of channels is @n_chan + 2.
692  *
693  * An invariant: shape >= alpha.
694  **/
695 void
696 art_pdf_composite_pixel_knockout_8(byte *dst,
697 				   const byte *backdrop, const byte *src,
698 				   int n_chan, gs_blend_mode_t blend_mode)
699 {
700     int i;
701     byte ct[ART_MAX_CHAN + 1];
702     byte src_shape;
703     byte backdrop_alpha;
704     byte dst_alpha;
705     bits32 src_opacity;
706     bits32 backdrop_weight, t_weight;
707     int tmp;
708 
709     if (src[n_chan] == 0)
710 	return;
711     if (src[n_chan + 1] == 255 && blend_mode == BLEND_MODE_Normal ||
712 	dst[n_chan] == 0) {
713 	/* this idiom is faster than memcpy (dst, src, n_chan + 2); for
714 	   expected small values of n_chan. */
715 	for (i = 0; i <= (n_chan + 1) >> 2; i++) {
716 	    ((bits32 *) dst)[i] = ((const bits32 *)src[i]);
717 	}
718 
719 	return;
720     }
721 
722 
723     src_shape = src[n_chan + 1];	/* $fs_i$ */
724     src_opacity = (255 * src[n_chan] + 0x80) / src_shape;	/* $qs_i$ */
725 #if 0
726     for (i = 0; i < (n_chan + 3) >> 2; i++) {
727 	((bits32 *) src_tmp)[i] = ((const bits32 *)src[i]);
728     }
729     src_tmp[n_chan] = src_opacity;
730 
731     for (i = 0; i <= n_chan >> 2; i++) {
732 	((bits32 *) tmp)[i] = ((bits32 *) backdrop[i]);
733     }
734 #endif
735 
736     backdrop_scale = if (blend_mode == BLEND_MODE_Normal) {
737 	/* Do simple compositing of source over backdrop */
738 	for (i = 0; i < n_chan; i++) {
739 	    c_s = src[i];
740 	    c_b = dst[i];
741 	    tmp = (c_b << 16) + ct_scale * (c_s - c_b) + 0x8000;
742 	    ct[i] = tmp >> 16;
743 	}
744     } else {
745 	/* Do compositing with blending */
746 	byte blend[ART_MAX_CHAN];
747 
748 	art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode);
749 	for (i = 0; i < n_chan; i++) {
750 	    int c_bl;		/* Result of blend function */
751 	    int c_mix;		/* Blend result mixed with source color */
752 
753 	    c_s = src[i];
754 	    c_b = dst[i];
755 	    c_bl = blend[i];
756 	    tmp = a_b * (((int)c_bl) - ((int)c_s)) + 0x80;
757 	    c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
758 	    tmp = (c_b << 16) + ct_scale * (c_mix - c_b) + 0x8000;
759 	    ct[i] = tmp >> 16;
760 	}
761     }
762 
763     /* do weighted average of $Ct$ using relative alpha contribution as weight */
764     backdrop_alpha = backdrop[n_chan];
765     tmp = (0xff - blend_alpha) * (0xff - backdrop_alpha) + 0x80;
766     dst_alpha = 0xff - (((tmp >> 8) + tmp) >> 8);
767     dst[n_chan] = dst_alpha;
768     t_weight = ((blend_alpha << 16) + 0x8000) / dst_alpha;
769     for (i = 0; i < n_chan; i++) {
770 
771     }
772 }
773 #endif
774 
775 void
art_pdf_uncomposite_group_8(byte * dst,const byte * backdrop,const byte * src,byte src_alpha_g,int n_chan)776 art_pdf_uncomposite_group_8(byte *dst,
777 			    const byte *backdrop,
778 			    const byte *src, byte src_alpha_g, int n_chan)
779 {
780     byte backdrop_alpha = backdrop[n_chan];
781     int i;
782     int tmp;
783     int scale;
784 
785     dst[n_chan] = src_alpha_g;
786 
787     if (src_alpha_g == 0)
788 	return;
789 
790     scale = (backdrop_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
791 	backdrop_alpha;
792     for (i = 0; i < n_chan; i++) {
793 	int si, di;
794 
795 	si = src[i];
796 	di = backdrop[i];
797 	tmp = (si - di) * scale + 0x80;
798 	tmp = si + ((tmp + (tmp >> 8)) >> 8);
799 
800 	/* todo: it should be possible to optimize these cond branches */
801 	if (tmp < 0)
802 	    tmp = 0;
803 	if (tmp > 255)
804 	    tmp = 255;
805 	dst[i] = tmp;
806     }
807 
808 }
809 
810 void
art_pdf_recomposite_group_8(byte * dst,byte * dst_alpha_g,const byte * src,byte src_alpha_g,int n_chan,byte alpha,gs_blend_mode_t blend_mode)811 art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g,
812 			    const byte *src, byte src_alpha_g,
813 			    int n_chan,
814 			    byte alpha, gs_blend_mode_t blend_mode)
815 {
816     byte dst_alpha;
817     int i;
818     int tmp;
819     int scale;
820 
821     if (src_alpha_g == 0)
822 	return;
823 
824     if (blend_mode == BLEND_MODE_Normal && alpha == 255) {
825 	/* In this case, uncompositing and recompositing cancel each
826 	   other out. Note: if the reason that alpha == 255 is that
827 	   there is no constant mask and no soft mask, then this
828 	   operation should be optimized away at a higher level. */
829 	for (i = 0; i <= n_chan >> 2; i++)
830 	    ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
831 	if (dst_alpha_g != NULL) {
832 	    tmp = (255 - *dst_alpha_g) * (255 - src_alpha_g) + 0x80;
833 	    *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
834 	}
835 	return;
836     } else {
837 	/* "interesting" blend mode */
838 	byte ca[ART_MAX_CHAN + 1];	/* $C, \alpha$ */
839 
840 	dst_alpha = dst[n_chan];
841 	if (src_alpha_g == 255 || dst_alpha == 0) {
842 	    for (i = 0; i < (n_chan + 3) >> 2; i++)
843 		((bits32 *) ca)[i] = ((const bits32 *)src)[i];
844 	} else {
845 	    /* Uncomposite the color. In other words, solve
846 	       "src = (ca, src_alpha_g) over dst" for ca */
847 
848 	    /* todo (maybe?): replace this code with call to
849 	       art_pdf_uncomposite_group_8() to reduce code
850 	       duplication. */
851 
852 	    scale = (dst_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
853 		dst_alpha;
854 	    for (i = 0; i < n_chan; i++) {
855 		int si, di;
856 
857 		si = src[i];
858 		di = dst[i];
859 		tmp = (si - di) * scale + 0x80;
860 		tmp = si + ((tmp + (tmp >> 8)) >> 8);
861 
862 		/* todo: it should be possible to optimize these cond branches */
863 		if (tmp < 0)
864 		    tmp = 0;
865 		if (tmp > 255)
866 		    tmp = 255;
867 		ca[i] = tmp;
868 	    }
869 	}
870 
871 	tmp = src_alpha_g * alpha + 0x80;
872 	tmp = (tmp + (tmp >> 8)) >> 8;
873 	ca[n_chan] = tmp;
874 	if (dst_alpha_g != NULL) {
875 	    tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80;
876 	    *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
877 	}
878 	art_pdf_composite_pixel_alpha_8(dst, ca, n_chan, blend_mode);
879     }
880     /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
881 }
882 
883 void
art_pdf_composite_group_8(byte * dst,byte * dst_alpha_g,const byte * src,int n_chan,byte alpha,gs_blend_mode_t blend_mode)884 art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g,
885 			  const byte *src,
886 			  int n_chan, byte alpha, gs_blend_mode_t blend_mode)
887 {
888     byte src_alpha;		/* $\alpha g_n$ */
889     byte src_tmp[ART_MAX_CHAN + 1];
890     int i;
891     int tmp;
892 
893     if (alpha == 255) {
894 	art_pdf_composite_pixel_alpha_8(dst, src, n_chan, blend_mode);
895 	if (dst_alpha_g != NULL) {
896 	    tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
897 	    *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
898 	}
899     } else {
900 	src_alpha = src[n_chan];
901 	if (src_alpha == 0)
902 	    return;
903 	for (i = 0; i < (n_chan + 3) >> 2; i++)
904 	    ((bits32 *) src_tmp)[i] = ((const bits32 *)src)[i];
905 	tmp = src_alpha * alpha + 0x80;
906 	src_tmp[n_chan] = (tmp + (tmp >> 8)) >> 8;
907 	art_pdf_composite_pixel_alpha_8(dst, src_tmp, n_chan, blend_mode);
908 	if (dst_alpha_g != NULL) {
909 	    tmp = (255 - *dst_alpha_g) * (255 - src_tmp[n_chan]) + 0x80;
910 	    *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
911 	}
912     }
913 }
914 
915 void
art_pdf_composite_knockout_simple_8(byte * dst,byte * dst_shape,const byte * src,int n_chan,byte opacity)916 art_pdf_composite_knockout_simple_8(byte *dst,
917 				    byte *dst_shape,
918 				    const byte *src,
919 				    int n_chan, byte opacity)
920 {
921     byte src_shape = src[n_chan];
922     int i;
923 
924     if (src_shape == 0)
925 	return;
926     else if (src_shape == 255) {
927 	for (i = 0; i < (n_chan + 3) >> 2; i++)
928 	    ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
929 	dst[n_chan] = opacity;
930 	if (dst_shape != NULL)
931 	    *dst_shape = 255;
932     } else {
933 	/* Use src_shape to interpolate (in premultiplied alpha space)
934 	   between dst and (src, opacity). */
935 	int dst_alpha = dst[n_chan];
936 	byte result_alpha;
937 	int tmp;
938 
939 	tmp = (opacity - dst_alpha) * src_shape + 0x80;
940 	result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
941 
942 	if (result_alpha != 0)
943 	    for (i = 0; i < n_chan; i++) {
944 		/* todo: optimize this - can strength-reduce so that
945 		   inner loop is a single interpolation */
946 		tmp = dst[i] * dst_alpha * (255 - src_shape) +
947 		    ((int)src[i]) * opacity * src_shape + (result_alpha << 7);
948 		dst[i] = tmp / (result_alpha * 255);
949 	    }
950 	dst[n_chan] = result_alpha;
951 
952 	/* union in dst_shape if non-null */
953 	if (dst_shape != NULL) {
954 	    tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
955 	    *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
956 	}
957     }
958 }
959 
960 void
art_pdf_composite_knockout_isolated_8(byte * dst,byte * dst_shape,const byte * src,int n_chan,byte shape,byte alpha_mask,byte shape_mask)961 art_pdf_composite_knockout_isolated_8(byte *dst,
962 				      byte *dst_shape,
963 				      const byte *src,
964 				      int n_chan,
965 				      byte shape,
966 				      byte alpha_mask, byte shape_mask)
967 {
968     int tmp;
969     int i;
970 
971     if (shape == 0)
972 	return;
973     else if ((shape & shape_mask) == 255) {
974 	for (i = 0; i < (n_chan + 3) >> 2; i++)
975 	    ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
976 	tmp = src[n_chan] * alpha_mask + 0x80;
977 	dst[n_chan] = (tmp + (tmp >> 8)) >> 8;
978 	if (dst_shape != NULL)
979 	    *dst_shape = 255;
980     } else {
981 	/* Use src_shape to interpolate (in premultiplied alpha space)
982 	   between dst and (src, opacity). */
983 	byte src_shape, src_alpha;
984 	int dst_alpha = dst[n_chan];
985 	byte result_alpha;
986 	int tmp;
987 
988 	tmp = shape * shape_mask + 0x80;
989 	src_shape = (tmp + (tmp >> 8)) >> 8;
990 
991 	tmp = src[n_chan] * alpha_mask + 0x80;
992 	src_alpha = (tmp + (tmp >> 8)) >> 8;
993 
994 	tmp = (src_alpha - dst_alpha) * src_shape + 0x80;
995 	result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
996 
997 	if (result_alpha != 0)
998 	    for (i = 0; i < n_chan; i++) {
999 		/* todo: optimize this - can strength-reduce so that
1000 		   inner loop is a single interpolation */
1001 		tmp = dst[i] * dst_alpha * (255 - src_shape) +
1002 		    ((int)src[i]) * src_alpha * src_shape +
1003 		    (result_alpha << 7);
1004 		dst[i] = tmp / (result_alpha * 255);
1005 	    }
1006 	dst[n_chan] = result_alpha;
1007 
1008 	/* union in dst_shape if non-null */
1009 	if (dst_shape != NULL) {
1010 	    tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
1011 	    *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
1012 	}
1013     }
1014 }
1015 
1016 void
art_pdf_composite_knockout_8(byte * dst,byte * dst_alpha_g,const byte * backdrop,const byte * src,int n_chan,byte shape,byte alpha_mask,byte shape_mask,gs_blend_mode_t blend_mode)1017 art_pdf_composite_knockout_8(byte *dst,
1018 			     byte *dst_alpha_g,
1019 			     const byte *backdrop,
1020 			     const byte *src,
1021 			     int n_chan,
1022 			     byte shape,
1023 			     byte alpha_mask,
1024 			     byte shape_mask, gs_blend_mode_t blend_mode)
1025 {
1026     /* This implementation follows the Adobe spec pretty closely, rather
1027        than trying to do anything clever. For example, in the case of a
1028        Normal blend_mode when the top group is non-isolated, uncompositing
1029        and recompositing is more work than needed. So be it. Right now,
1030        I'm more worried about manageability than raw performance. */
1031     byte alpha_t;
1032     byte src_alpha, src_shape;
1033     byte src_opacity;
1034     byte ct[ART_MAX_CHAN];
1035     byte backdrop_alpha;
1036     byte alpha_g_i_1, alpha_g_i, alpha_i;
1037     int tmp;
1038     int i;
1039     int scale_b;
1040     int scale_src;
1041 
1042     if (shape == 0 || shape_mask == 0)
1043 	return;
1044 
1045     tmp = shape * shape_mask + 0x80;
1046     /* $f s_i$ */
1047     src_shape = (tmp + (tmp >> 8)) >> 8;
1048 
1049     tmp = src[n_chan] * alpha_mask + 0x80;
1050     src_alpha = (tmp + (tmp >> 8)) >> 8;
1051 
1052     /* $q s_i$ */
1053     src_opacity = (src_alpha * 510 + src_shape) / (2 * src_shape);
1054 
1055     /* $\alpha t$, \alpha g_b is always zero for knockout groups */
1056     alpha_t = src_opacity;
1057 
1058     /* $\alpha b$ */
1059     backdrop_alpha = backdrop[n_chan];
1060 
1061     tmp = (0xff - src_opacity) * backdrop_alpha;
1062     /* $(1 - q s_i) \cdot alpha_b$ scaled by 2^16 */
1063     scale_b = tmp + (tmp >> 7) + (tmp >> 14);
1064 
1065     /* $q s_i$ scaled by 2^16 */
1066     scale_src = (src_opacity << 8) + (src_opacity) + (src_opacity >> 7);
1067 
1068     /* Do simple compositing of source over backdrop */
1069     if (blend_mode == BLEND_MODE_Normal) {
1070 	for (i = 0; i < n_chan; i++) {
1071 	    int c_s;
1072 	    int c_b;
1073 
1074 	    c_s = src[i];
1075 	    c_b = backdrop[i];
1076 	    tmp = (c_b << 16) * scale_b + (c_s - c_b) + scale_src + 0x8000;
1077 	    ct[i] = tmp >> 16;
1078 	}
1079     } else {
1080 	byte blend[ART_MAX_CHAN];
1081 
1082 	art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode);
1083 	for (i = 0; i < n_chan; i++) {
1084 	    int c_s;
1085 	    int c_b;
1086 	    int c_bl;		/* Result of blend function */
1087 	    int c_mix;		/* Blend result mixed with source color */
1088 
1089 	    c_s = src[i];
1090 	    c_b = backdrop[i];
1091 	    c_bl = blend[i];
1092 	    tmp = backdrop_alpha * (c_bl - ((int)c_s)) + 0x80;
1093 	    c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1094 	    tmp = (c_b << 16) * scale_b + (c_mix - c_b) + scale_src + 0x8000;
1095 	    ct[i] = tmp >> 16;
1096 	}
1097     }
1098 
1099     /* $\alpha g_{i - 1}$ */
1100     alpha_g_i_1 = *dst_alpha_g;
1101 
1102     tmp = src_shape * (((int)alpha_t) - alpha_g_i_1) + 0x80;
1103     /* $\alpha g_i$ */
1104     alpha_g_i = alpha_g_i_1 + ((tmp + (tmp >> 8)) >> 8);
1105 
1106     tmp = (0xff - backdrop_alpha) * (0xff - alpha_g_i) + 0x80;
1107     /* $\alpha_i$ */
1108     alpha_i = 0xff - ((tmp + (tmp >> 8)) >> 8);
1109 
1110     if (alpha_i > 0) {
1111 	int scale_dst;
1112 	int scale_t;
1113 	byte dst_alpha;
1114 
1115 	/* $f s_i / \alpha_i$ scaled by 2^16 */
1116 	scale_t = ((src_shape << 17) + alpha_i) / (2 * alpha_i);
1117 
1118 	/* $\alpha_{i - 1}$ */
1119 	dst_alpha = dst[n_chan];
1120 
1121 	tmp = (1 - src_shape) * dst_alpha;
1122 	tmp = (tmp << 9) + (tmp << 1) + (tmp >> 7) + alpha_i;
1123 	scale_dst = tmp / (2 * alpha_i);
1124 
1125 	for (i = 0; i < n_chan; i++) {
1126 	    tmp = dst[i] * scale_dst + ct[i] * scale_t + 0x8000;
1127 	    /* todo: clamp? */
1128 	    dst[i] = tmp >> 16;
1129 	}
1130     }
1131     dst[n_chan] = alpha_i;
1132     *dst_alpha_g = alpha_g_i;
1133 }
1134