1 /*
2  * Copyright © 2004 Eric Anholt
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Eric Anholt not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  Eric Anholt makes no
11  * representations about the suitability of this software for any purpose.  It
12  * is provided "as is" without express or implied warranty.
13  *
14  * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  */
22 
23 #include <stdlib.h>
24 
25 #include "rendercheck.h"
26 
27 #define mult_chan(src, dst, Fa, Fb) \
28 	min((double)(src) * (double)(Fa) + (double)(dst) * (double)(Fb), 1.0)
29 
30 static double
calc_op(int op,double src,double dst,double srca,double dsta)31 calc_op(int op, double src, double dst, double srca, double dsta)
32 {
33 	double Fa, Fb;
34 
35 	switch (op) {
36 		case PictOpClear:
37 		case PictOpDisjointClear:
38 		case PictOpConjointClear:
39 			return mult_chan(src, dst, 0.0, 0.0);
40 		case PictOpSrc:
41 		case PictOpDisjointSrc:
42 		case PictOpConjointSrc:
43 			return mult_chan(src, dst, 1.0, 0.0);
44 		case PictOpDst:
45 		case PictOpDisjointDst:
46 		case PictOpConjointDst:
47 			return mult_chan(src, dst, 0.0, 1.0);
48 		case PictOpOver:
49 			return mult_chan(src, dst, 1.0, 1.0 - srca);
50 		case PictOpOverReverse:
51 			return mult_chan(src, dst, 1.0 - dsta, 1.0);
52 		case PictOpIn:
53 			return mult_chan(src, dst, dsta, 0.0);
54 		case PictOpInReverse:
55 			return mult_chan(src, dst, 0.0, srca);
56 		case PictOpOut:
57 			return mult_chan(src, dst, 1.0 - dsta, 0.0);
58 		case PictOpOutReverse:
59 			return mult_chan(src, dst, 0.0, 1.0 - srca);
60 		case PictOpAtop:
61 			return mult_chan(src, dst, dsta, 1.0 - srca);
62 		case PictOpAtopReverse:
63 			return mult_chan(src, dst, 1.0 - dsta,  srca);
64 		case PictOpXor:
65 			return mult_chan(src, dst, 1.0 - dsta, 1.0 - srca);
66 		case PictOpAdd:
67 			return mult_chan(src, dst, 1.0, 1.0);
68 			break;
69 		case PictOpSaturate:
70 		case PictOpDisjointOverReverse:
71 			if (srca == 0.0)
72 				Fa = 1.0;
73 			else
74 				Fa = min(1.0, (1.0 - dsta) / srca);
75 			return mult_chan(src, dst, Fa, 1.0);
76 		case PictOpDisjointOver:
77 			if (dsta == 0.0)
78 				Fb = 1.0;
79 			else
80 				Fb = min(1.0, (1.0 - srca) / dsta);
81 			return mult_chan(src, dst, 1.0, Fb);
82 		case PictOpDisjointIn:
83 			if (srca == 0.0)
84 				Fa = 0.0;
85 			else
86 				Fa = max(0.0, 1.0 - (1.0 - dsta) / srca);
87 			return mult_chan(src, dst, Fa, 0.0);
88 		case PictOpDisjointInReverse:
89 			if (dsta == 0.0)
90 				Fb = 0.0;
91 			else
92 				Fb = max(0.0, 1.0 - (1.0 - srca) / dsta);
93 			return mult_chan(src, dst, 0.0, Fb);
94 		case PictOpDisjointOut:
95 			if (srca == 0.0)
96 				Fa = 1.0;
97 			else
98 				Fa = min(1.0, (1.0 - dsta) / srca);
99 			return mult_chan(src, dst, Fa, 0.0);
100 		case PictOpDisjointOutReverse:
101 			if (dsta == 0.0)
102 				Fb = 1.0;
103 			else
104 				Fb = min(1.0, (1.0 - srca) / dsta);
105 			return mult_chan(src, dst, 0.0, Fb);
106 		case PictOpDisjointAtop:
107 			if (srca == 0.0)
108 				Fa = 0.0;
109 			else
110 				Fa = max(0.0, 1.0 - (1.0 - dsta) / srca);
111 			if (dsta == 0.0)
112 				Fb = 1.0;
113 			else
114 				Fb = min(1.0, (1.0 - srca) / dsta);
115 			return mult_chan(src, dst, Fa, Fb);
116 		case PictOpDisjointAtopReverse:
117 			if (srca == 0.0)
118 				Fa = 1.0;
119 			else
120 				Fa = min(1.0, (1.0 - dsta) / srca);
121 			if (dsta == 0.0)
122 				Fb = 0.0;
123 			else
124 				Fb = max(0.0, 1.0 - (1.0 - srca) / dsta);
125 			return mult_chan(src, dst, Fa, Fb);
126 		case PictOpDisjointXor:
127 			if (srca == 0.0)
128 				Fa = 1.0;
129 			else
130 				Fa = min(1.0, (1.0 - dsta) / srca);
131 			if (dsta == 0.0)
132 				Fb = 1.0;
133 			else
134 				Fb = min(1.0, (1.0 - srca) / dsta);
135 			return mult_chan(src, dst, Fa, Fb);
136 		case PictOpConjointOver:
137 			if (dsta == 0.0)
138 				Fb = 0.0;
139 			else
140 				Fb = max(0.0, 1.0 - srca / dsta);
141 			return mult_chan(src, dst, 1.0, Fb);
142 		case PictOpConjointOverReverse:
143 			if (srca == 0.0)
144 				Fa = 0.0;
145 			else
146 				Fa = max(0.0, 1.0 - dsta / srca);
147 			return mult_chan(src, dst, Fa, 1.0);
148 		case PictOpConjointIn:
149 			if (srca == 0.0)
150 				Fa = 1.0;
151 			else
152 				Fa = min(1.0, dsta / srca);
153 			return mult_chan(src, dst, Fa, 0.0);
154 		case PictOpConjointInReverse:
155 			if (dsta == 0.0)
156 				Fb = 1.0;
157 			else
158 				Fb = min(1.0, srca / dsta);
159 			return mult_chan(src, dst, 0.0, Fb);
160 		case PictOpConjointOut:
161 			if (srca == 0.0)
162 				Fa = 0.0;
163 			else
164 				Fa = max(0.0, 1.0 - dsta / srca);
165 			return mult_chan(src, dst, Fa, 0.0);
166 		case PictOpConjointOutReverse:
167 			if (dsta == 0.0)
168 				Fb = 0.0;
169 			else
170 				Fb = max(0.0, 1.0 - srca / dsta);
171 			return mult_chan(src, dst, 0.0, Fb);
172 		case PictOpConjointAtop:
173 			if (srca == 0.0)
174 				Fa = 1.0;
175 			else
176 				Fa = min(1.0, dsta / srca);
177 			if (dsta == 0.0)
178 				Fb = 0.0;
179 			else
180 				Fb = max(0.0, 1.0 - srca / dsta);
181 			return mult_chan(src, dst, Fa, Fb);
182 		case PictOpConjointAtopReverse:
183 			if (srca == 0.0)
184 				Fa = 0.0;
185 			else
186 				Fa = max(0.0, 1.0 - dsta / srca);
187 			if (dsta == 0.0)
188 				Fb = 1.0;
189 			else
190 				Fb = min(1.0, srca / dsta);
191 			return mult_chan(src, dst, Fa, Fb);
192 		case PictOpConjointXor:
193 			if (srca == 0.0)
194 				Fa = 0.0;
195 			else
196 				Fa = max(0.0, 1.0 - dsta / srca);
197 			if (dsta == 0.0)
198 				Fb = 0.0;
199 			else
200 				Fb = max(0.0, 1.0 - srca / dsta);
201 			return mult_chan(src, dst, Fa, Fb);
202 		default:
203 			abort();
204 	}
205 }
206 
207 void
do_composite(int op,const color4d * src,const color4d * mask,const color4d * dst,color4d * result,Bool componentAlpha)208 do_composite(int op,
209 	     const color4d *src,
210 	     const color4d *mask,
211 	     const color4d *dst,
212 	     color4d *result,
213 	     Bool componentAlpha)
214 {
215 	color4d srcval, srcalpha;
216 
217 	if (mask != NULL && componentAlpha) {
218 		srcval.r = src->r * mask->r;
219 		srcval.g = src->g * mask->g;
220 		srcval.b = src->b * mask->b;
221 		srcval.a = src->a * mask->a;
222 		srcalpha.r = src->a * mask->r;
223 		srcalpha.g = src->a * mask->g;
224 		srcalpha.b = src->a * mask->b;
225 		srcalpha.a = src->a * mask->a;
226 	} else if (mask != NULL) {
227 		srcval.r = src->r * mask->a;
228 		srcval.g = src->g * mask->a;
229 		srcval.b = src->b * mask->a;
230 		srcval.a = src->a * mask->a;
231 		srcalpha.r = src->a * mask->a;
232 		srcalpha.g = src->a * mask->a;
233 		srcalpha.b = src->a * mask->a;
234 		srcalpha.a = src->a * mask->a;
235 	} else {
236 		srcval = *src;
237 		srcalpha.r = src->a;
238 		srcalpha.g = src->a;
239 		srcalpha.b = src->a;
240 		srcalpha.a = src->a;
241 	}
242 
243 	result->r = calc_op(op, srcval.r, dst->r, srcalpha.r, dst->a);
244 	result->g = calc_op(op, srcval.g, dst->g, srcalpha.g, dst->a);
245 	result->b = calc_op(op, srcval.b, dst->b, srcalpha.b, dst->a);
246 	result->a = calc_op(op, srcval.a, dst->a, srcalpha.a, dst->a);
247 }
248