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