/src/mupdf/source/fitz/shade.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2021 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include <string.h> |
26 | | #include <math.h> |
27 | | |
28 | | typedef struct |
29 | | { |
30 | | fz_shade *shade; |
31 | | fz_shade_prepare_fn *prepare; |
32 | | fz_shade_process_fn *process; |
33 | | void *process_arg; |
34 | | int ncomp; |
35 | | } fz_mesh_processor; |
36 | | |
37 | 39.5k | #define SWAP(a,b) {fz_vertex *t = (a); (a) = (b); (b) = t;} |
38 | | |
39 | | static inline void |
40 | | paint_tri(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2) |
41 | 14.0k | { |
42 | 14.0k | if (painter->process) |
43 | 14.0k | { |
44 | 14.0k | painter->process(ctx, painter->process_arg, v0, v1, v2); |
45 | 14.0k | } |
46 | 14.0k | } |
47 | | |
48 | | static inline void |
49 | | paint_quad(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2, fz_vertex *v3) |
50 | 1.56M | { |
51 | | /* For a quad with corners (in clockwise or anticlockwise order) are |
52 | | * v0, v1, v2, v3. We can choose to split in in various different ways. |
53 | | * Arbitrarily we can pick v0, v1, v3 for the first triangle. We then |
54 | | * have to choose between v1, v2, v3 or v3, v2, v1 (or their equivalent |
55 | | * rotations) for the second triangle. |
56 | | * |
57 | | * v1, v2, v3 has the property that both triangles share the same |
58 | | * winding (useful if we were ever doing simple back face culling). |
59 | | * |
60 | | * v3, v2, v1 has the property that all the 'shared' edges (both |
61 | | * within this quad, and with adjacent quads) are walked in the same |
62 | | * direction every time. This can be useful in that depending on the |
63 | | * implementation/rounding etc walking from A -> B can hit different |
64 | | * pixels than walking from B->A. |
65 | | * |
66 | | * In the event neither of these things matter at the moment, as all |
67 | | * the process functions where it matters order the edges from top to |
68 | | * bottom before walking them. |
69 | | */ |
70 | 1.56M | if (painter->process) |
71 | 1.56M | { |
72 | 1.56M | painter->process(ctx, painter->process_arg, v0, v1, v3); |
73 | 1.56M | painter->process(ctx, painter->process_arg, v3, v2, v1); |
74 | 1.56M | } |
75 | 1.56M | } |
76 | | |
77 | | static inline void |
78 | | fz_prepare_color(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v, float *c) |
79 | 5.40M | { |
80 | 5.40M | if (painter->prepare) |
81 | 5.40M | { |
82 | 5.40M | painter->prepare(ctx, painter->process_arg, v, c); |
83 | 5.40M | } |
84 | 5.40M | } |
85 | | |
86 | | static inline void |
87 | | fz_prepare_vertex(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v, fz_matrix ctm, float x, float y, float *c) |
88 | 225k | { |
89 | 225k | v->p = fz_transform_point_xy(x, y, ctm); |
90 | 225k | if (painter->prepare) |
91 | 225k | { |
92 | 225k | painter->prepare(ctx, painter->process_arg, v, c); |
93 | 225k | } |
94 | 225k | } |
95 | | |
96 | | static void |
97 | | fz_process_shade_type1(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
98 | 2 | { |
99 | 2 | float *p = shade->u.f.fn_vals; |
100 | 2 | int xdivs = shade->u.f.xdivs; |
101 | 2 | int ydivs = shade->u.f.ydivs; |
102 | 2 | float x0 = shade->u.f.domain[0][0]; |
103 | 2 | float y0 = shade->u.f.domain[0][1]; |
104 | 2 | float x1 = shade->u.f.domain[1][0]; |
105 | 2 | float y1 = shade->u.f.domain[1][1]; |
106 | 2 | int xx, yy; |
107 | 2 | float y, yn, x; |
108 | 2 | fz_vertex vs[2][2]; |
109 | 2 | fz_vertex *v = vs[0]; |
110 | 2 | fz_vertex *vn = vs[1]; |
111 | 2 | int n = fz_colorspace_n(ctx, shade->colorspace); |
112 | | |
113 | 2 | ctm = fz_concat(shade->u.f.matrix, ctm); |
114 | | |
115 | 2 | y = y0; |
116 | 130 | for (yy = 0; yy < ydivs; yy++) |
117 | 128 | { |
118 | 128 | yn = y0 + (y1 - y0) * (yy + 1) / ydivs; |
119 | | |
120 | 128 | x = x0; |
121 | | |
122 | 128 | fz_prepare_vertex(ctx, painter, &v[0], ctm, x, y, p); |
123 | 128 | p += n; |
124 | 128 | fz_prepare_vertex(ctx, painter, &v[1], ctm, x, yn, p + xdivs * n); |
125 | | |
126 | 8.32k | for (xx = 0; xx < xdivs; xx++) |
127 | 8.19k | { |
128 | 8.19k | x = x0 + (x1 - x0) * (xx + 1) / xdivs; |
129 | | |
130 | 8.19k | fz_prepare_vertex(ctx, painter, &vn[0], ctm, x, y, p); |
131 | 8.19k | p += n; |
132 | 8.19k | fz_prepare_vertex(ctx, painter, &vn[1], ctm, x, yn, p + xdivs * n); |
133 | | |
134 | 8.19k | paint_quad(ctx, painter, &v[0], &vn[0], &vn[1], &v[1]); |
135 | 8.19k | SWAP(v,vn); |
136 | 8.19k | } |
137 | 128 | y = yn; |
138 | 128 | } |
139 | 2 | } |
140 | | |
141 | 20 | #define HUGENUM 32000 /* how far to extend linear/radial shadings */ |
142 | | |
143 | | static fz_point |
144 | | fz_point_on_circle(fz_point p, float r, float theta) |
145 | 132k | { |
146 | 132k | p.x = p.x + cosf(theta) * r; |
147 | 132k | p.y = p.y + sinf(theta) * r; |
148 | 132k | return p; |
149 | 132k | } |
150 | | |
151 | | static void |
152 | | fz_process_shade_type2(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter, fz_rect scissor) |
153 | 57.9k | { |
154 | 57.9k | fz_point p0, p1, dir; |
155 | 57.9k | fz_vertex v0, v1, v2, v3; |
156 | 57.9k | fz_vertex e0, e1; |
157 | 57.9k | float theta; |
158 | 57.9k | float zero = 0; |
159 | 57.9k | float one = 1; |
160 | 57.9k | float r; |
161 | | |
162 | 57.9k | p0.x = shade->u.l_or_r.coords[0][0]; |
163 | 57.9k | p0.y = shade->u.l_or_r.coords[0][1]; |
164 | 57.9k | p1.x = shade->u.l_or_r.coords[1][0]; |
165 | 57.9k | p1.y = shade->u.l_or_r.coords[1][1]; |
166 | 57.9k | dir.x = p0.y - p1.y; |
167 | 57.9k | dir.y = p1.x - p0.x; |
168 | 57.9k | p0 = fz_transform_point(p0, ctm); |
169 | 57.9k | p1 = fz_transform_point(p1, ctm); |
170 | 57.9k | dir = fz_transform_vector(dir, ctm); |
171 | 57.9k | theta = atan2f(dir.y, dir.x); |
172 | | |
173 | 57.9k | if (fz_is_infinite_rect(scissor)) { |
174 | 0 | r = HUGENUM; /* Not ideal, but it'll do for now */ |
175 | 57.9k | } else { |
176 | 57.9k | float x = p0.x - scissor.x0; |
177 | 57.9k | float y = p0.y - scissor.y0; |
178 | 57.9k | if (x < scissor.x1 - p0.x) |
179 | 56.1k | x = scissor.x1 - p0.x; |
180 | 57.9k | if (x < p0.x - scissor.x1) |
181 | 0 | x = p0.x - scissor.x1; |
182 | 57.9k | if (x < scissor.x1 - p1.x) |
183 | 530 | x = scissor.x1 - p1.x; |
184 | 57.9k | if (y < scissor.y1 - p0.y) |
185 | 19.7k | y = scissor.y1 - p0.y; |
186 | 57.9k | if (y < p0.y - scissor.y1) |
187 | 0 | y = p0.y - scissor.y1; |
188 | 57.9k | if (y < scissor.y1 - p1.y) |
189 | 1.28k | y = scissor.y1 - p1.y; |
190 | 57.9k | r = x+y; |
191 | 57.9k | } |
192 | 57.9k | v0.p = fz_point_on_circle(p0, r, theta); |
193 | 57.9k | v1.p = fz_point_on_circle(p1, r, theta); |
194 | 57.9k | v2.p.x = 2*p0.x - v0.p.x; |
195 | 57.9k | v2.p.y = 2*p0.y - v0.p.y; |
196 | 57.9k | v3.p.x = 2*p1.x - v1.p.x; |
197 | 57.9k | v3.p.y = 2*p1.y - v1.p.y; |
198 | | |
199 | 57.9k | fz_prepare_color(ctx, painter, &v0, &zero); |
200 | 57.9k | fz_prepare_color(ctx, painter, &v1, &one); |
201 | 57.9k | fz_prepare_color(ctx, painter, &v2, &zero); |
202 | 57.9k | fz_prepare_color(ctx, painter, &v3, &one); |
203 | | |
204 | 57.9k | paint_quad(ctx, painter, &v0, &v2, &v3, &v1); |
205 | | |
206 | 57.9k | if (shade->u.l_or_r.extend[0] || shade->u.l_or_r.extend[1]) { |
207 | 57.9k | float d = fabsf(p1.x - p0.x); |
208 | 57.9k | float e = fabsf(p1.y - p0.y); |
209 | 57.9k | if (d < e) |
210 | 4.84k | d = e; |
211 | 57.9k | if (d != 0) |
212 | 57.9k | r /= d; |
213 | 57.9k | } |
214 | 57.9k | if (shade->u.l_or_r.extend[0]) |
215 | 57.9k | { |
216 | 57.9k | e0.p.x = v0.p.x - (p1.x - p0.x) * r; |
217 | 57.9k | e0.p.y = v0.p.y - (p1.y - p0.y) * r; |
218 | 57.9k | fz_prepare_color(ctx, painter, &e0, &zero); |
219 | | |
220 | 57.9k | e1.p.x = v2.p.x - (p1.x - p0.x) * r; |
221 | 57.9k | e1.p.y = v2.p.y - (p1.y - p0.y) * r; |
222 | 57.9k | fz_prepare_color(ctx, painter, &e1, &zero); |
223 | | |
224 | 57.9k | paint_quad(ctx, painter, &e0, &v0, &v2, &e1); |
225 | 57.9k | } |
226 | | |
227 | 57.9k | if (shade->u.l_or_r.extend[1]) |
228 | 57.9k | { |
229 | 57.9k | e0.p.x = v1.p.x + (p1.x - p0.x) * r; |
230 | 57.9k | e0.p.y = v1.p.y + (p1.y - p0.y) * r; |
231 | 57.9k | fz_prepare_color(ctx, painter, &e0, &one); |
232 | | |
233 | 57.9k | e1.p.x = v3.p.x + (p1.x - p0.x) * r; |
234 | 57.9k | e1.p.y = v3.p.y + (p1.y - p0.y) * r; |
235 | 57.9k | fz_prepare_color(ctx, painter, &e1, &one); |
236 | | |
237 | 57.9k | paint_quad(ctx, painter, &e0, &v1, &v3, &e1); |
238 | 57.9k | } |
239 | 57.9k | } |
240 | | |
241 | | static void |
242 | | fz_paint_annulus(fz_context *ctx, fz_matrix ctm, |
243 | | fz_point p0, float r0, float c0, |
244 | | fz_point p1, float r1, float c1, |
245 | | int count, |
246 | | fz_mesh_processor *painter) |
247 | 56 | { |
248 | 56 | fz_vertex t0, t1, t2, t3, b0, b1, b2, b3; |
249 | 56 | float theta, step, a, b; |
250 | 56 | int i; |
251 | | |
252 | 56 | theta = atan2f(p1.y - p0.y, p1.x - p0.x); |
253 | 56 | step = FZ_PI / count; |
254 | | |
255 | 56 | a = 0; |
256 | 2.07k | for (i = 1; i <= count; i++) |
257 | 2.01k | { |
258 | 2.01k | b = i * step; |
259 | | |
260 | 2.01k | t0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + a), ctm); |
261 | 2.01k | t1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + b), ctm); |
262 | 2.01k | t2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + a), ctm); |
263 | 2.01k | t3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + b), ctm); |
264 | 2.01k | b0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - a), ctm); |
265 | 2.01k | b1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - b), ctm); |
266 | 2.01k | b2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - a), ctm); |
267 | 2.01k | b3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - b), ctm); |
268 | | |
269 | 2.01k | fz_prepare_color(ctx, painter, &t0, &c0); |
270 | 2.01k | fz_prepare_color(ctx, painter, &t1, &c0); |
271 | 2.01k | fz_prepare_color(ctx, painter, &t2, &c1); |
272 | 2.01k | fz_prepare_color(ctx, painter, &t3, &c1); |
273 | 2.01k | fz_prepare_color(ctx, painter, &b0, &c0); |
274 | 2.01k | fz_prepare_color(ctx, painter, &b1, &c0); |
275 | 2.01k | fz_prepare_color(ctx, painter, &b2, &c1); |
276 | 2.01k | fz_prepare_color(ctx, painter, &b3, &c1); |
277 | | |
278 | 2.01k | paint_quad(ctx, painter, &t0, &t2, &t3, &t1); |
279 | 2.01k | paint_quad(ctx, painter, &b0, &b2, &b3, &b1); |
280 | | |
281 | 2.01k | a = b; |
282 | 2.01k | } |
283 | 56 | } |
284 | | |
285 | | static void |
286 | | fz_process_shade_type3(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
287 | 19 | { |
288 | 19 | fz_point p0, p1; |
289 | 19 | float r0, r1; |
290 | 19 | fz_point e; |
291 | 19 | float er, rs; |
292 | 19 | int count; |
293 | | |
294 | 19 | p0.x = shade->u.l_or_r.coords[0][0]; |
295 | 19 | p0.y = shade->u.l_or_r.coords[0][1]; |
296 | 19 | r0 = shade->u.l_or_r.coords[0][2]; |
297 | | |
298 | 19 | p1.x = shade->u.l_or_r.coords[1][0]; |
299 | 19 | p1.y = shade->u.l_or_r.coords[1][1]; |
300 | 19 | r1 = shade->u.l_or_r.coords[1][2]; |
301 | | |
302 | | /* number of segments for a half-circle */ |
303 | 19 | count = 4 * sqrtf(fz_matrix_expansion(ctm) * fz_max(r0, r1)); |
304 | 19 | if (count < 3) |
305 | 1 | count = 3; |
306 | 19 | if (count > 1024) |
307 | 0 | count = 1024; |
308 | | |
309 | 19 | if (shade->u.l_or_r.extend[0]) |
310 | 18 | { |
311 | 18 | if (r0 < r1) |
312 | 17 | rs = r0 / (r0 - r1); |
313 | 1 | else |
314 | 1 | rs = -HUGENUM; |
315 | | |
316 | 18 | e.x = p0.x + (p1.x - p0.x) * rs; |
317 | 18 | e.y = p0.y + (p1.y - p0.y) * rs; |
318 | 18 | er = r0 + (r1 - r0) * rs; |
319 | | |
320 | 18 | fz_paint_annulus(ctx, ctm, e, er, 0, p0, r0, 0, count, painter); |
321 | 18 | } |
322 | | |
323 | 19 | fz_paint_annulus(ctx, ctm, p0, r0, 0, p1, r1, 1, count, painter); |
324 | | |
325 | 19 | if (shade->u.l_or_r.extend[1]) |
326 | 19 | { |
327 | 19 | if (r0 > r1) |
328 | 0 | rs = r1 / (r1 - r0); |
329 | 19 | else |
330 | 19 | rs = -HUGENUM; |
331 | | |
332 | 19 | e.x = p1.x + (p0.x - p1.x) * rs; |
333 | 19 | e.y = p1.y + (p0.y - p1.y) * rs; |
334 | 19 | er = r1 + (r0 - r1) * rs; |
335 | | |
336 | 19 | fz_paint_annulus(ctx, ctm, p1, r1, 1, e, er, 1, count, painter); |
337 | 19 | } |
338 | 19 | } |
339 | | |
340 | | static inline float read_sample(fz_context *ctx, fz_stream *stream, int bits, float min, float max) |
341 | 2.50M | { |
342 | | /* we use pow(2,x) because (1<<x) would overflow the math on 32-bit samples */ |
343 | 2.50M | float bitscale = 1 / (powf(2, bits) - 1); |
344 | 2.50M | return min + fz_read_bits(ctx, stream, bits) * (max - min) * bitscale; |
345 | 2.50M | } |
346 | | |
347 | | static void |
348 | | fz_process_shade_type4(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
349 | 62 | { |
350 | 62 | fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); |
351 | 62 | fz_vertex v[4]; |
352 | 62 | fz_vertex *va = &v[0]; |
353 | 62 | fz_vertex *vb = &v[1]; |
354 | 62 | fz_vertex *vc = &v[2]; |
355 | 62 | fz_vertex *vd = &v[3]; |
356 | 62 | int flag, i, ncomp = painter->ncomp; |
357 | 62 | int bpflag = shade->u.m.bpflag; |
358 | 62 | int bpcoord = shade->u.m.bpcoord; |
359 | 62 | int bpcomp = shade->u.m.bpcomp; |
360 | 62 | float x0 = shade->u.m.x0; |
361 | 62 | float x1 = shade->u.m.x1; |
362 | 62 | float y0 = shade->u.m.y0; |
363 | 62 | float y1 = shade->u.m.y1; |
364 | 62 | const float *c0 = shade->u.m.c0; |
365 | 62 | const float *c1 = shade->u.m.c1; |
366 | 62 | float x, y, c[FZ_MAX_COLORS]; |
367 | 62 | int first_triangle = 1; |
368 | | |
369 | 124 | fz_try(ctx) |
370 | 124 | { |
371 | 14.0k | while (!fz_is_eof_bits(ctx, stream)) |
372 | 14.0k | { |
373 | 14.0k | flag = fz_read_bits(ctx, stream, bpflag); |
374 | 14.0k | x = read_sample(ctx, stream, bpcoord, x0, x1); |
375 | 14.0k | y = read_sample(ctx, stream, bpcoord, y0, y1); |
376 | 56.0k | for (i = 0; i < ncomp; i++) |
377 | 42.0k | c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]); |
378 | 14.0k | fz_prepare_vertex(ctx, painter, vd, ctm, x, y, c); |
379 | | |
380 | 14.0k | if (first_triangle) |
381 | 62 | { |
382 | 62 | if (flag != 0) |
383 | 5 | { |
384 | 5 | fz_warn(ctx, "ignoring non-zero edge flags for first vertex in mesh"); |
385 | 5 | flag = 0; |
386 | 5 | } |
387 | 62 | first_triangle = 0; |
388 | 62 | } |
389 | | |
390 | 14.0k | switch (flag) |
391 | 14.0k | { |
392 | 12.5k | default: |
393 | 12.5k | fz_warn(ctx, "ignoring out of range edge flag in mesh"); |
394 | | /* fallthrough */ |
395 | | |
396 | 13.7k | case 0: /* start new triangle */ |
397 | 13.7k | SWAP(va, vd); |
398 | | |
399 | 13.7k | fz_read_bits(ctx, stream, bpflag); |
400 | 13.7k | x = read_sample(ctx, stream, bpcoord, x0, x1); |
401 | 13.7k | y = read_sample(ctx, stream, bpcoord, y0, y1); |
402 | 54.9k | for (i = 0; i < ncomp; i++) |
403 | 41.2k | c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]); |
404 | 13.7k | fz_prepare_vertex(ctx, painter, vb, ctm, x, y, c); |
405 | | |
406 | 13.7k | fz_read_bits(ctx, stream, bpflag); |
407 | 13.7k | x = read_sample(ctx, stream, bpcoord, x0, x1); |
408 | 13.7k | y = read_sample(ctx, stream, bpcoord, y0, y1); |
409 | 54.9k | for (i = 0; i < ncomp; i++) |
410 | 41.2k | c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]); |
411 | 13.7k | fz_prepare_vertex(ctx, painter, vc, ctm, x, y, c); |
412 | | |
413 | 13.7k | paint_tri(ctx, painter, va, vb, vc); |
414 | 13.7k | break; |
415 | | |
416 | 93 | case 1: /* Vb, Vc, Vd */ |
417 | 93 | SWAP(va, vb); |
418 | 93 | SWAP(vb, vc); |
419 | 93 | SWAP(vc, vd); |
420 | 93 | paint_tri(ctx, painter, va, vb, vc); |
421 | 93 | break; |
422 | | |
423 | 180 | case 2: /* Va, Vc, Vd */ |
424 | 180 | SWAP(vb, vc); |
425 | 180 | SWAP(vc, vd); |
426 | 180 | paint_tri(ctx, painter, va, vb, vc); |
427 | 180 | break; |
428 | 14.0k | } |
429 | 14.0k | } |
430 | 62 | } |
431 | 124 | fz_always(ctx) |
432 | 62 | { |
433 | 62 | fz_drop_stream(ctx, stream); |
434 | 62 | } |
435 | 62 | fz_catch(ctx) |
436 | 0 | { |
437 | 0 | fz_rethrow(ctx); |
438 | 0 | } |
439 | 62 | } |
440 | | |
441 | | static void |
442 | | fz_process_shade_type5(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
443 | 36 | { |
444 | 36 | fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); |
445 | 36 | fz_vertex *buf = NULL; |
446 | 36 | fz_vertex *ref = NULL; |
447 | 36 | int first; |
448 | 36 | int ncomp = painter->ncomp; |
449 | 36 | int i, k; |
450 | 36 | int vprow = shade->u.m.vprow; |
451 | 36 | int bpcoord = shade->u.m.bpcoord; |
452 | 36 | int bpcomp = shade->u.m.bpcomp; |
453 | 36 | float x0 = shade->u.m.x0; |
454 | 36 | float x1 = shade->u.m.x1; |
455 | 36 | float y0 = shade->u.m.y0; |
456 | 36 | float y1 = shade->u.m.y1; |
457 | 36 | const float *c0 = shade->u.m.c0; |
458 | 36 | const float *c1 = shade->u.m.c1; |
459 | 36 | float x, y, c[FZ_MAX_COLORS]; |
460 | | |
461 | 36 | fz_var(buf); |
462 | 36 | fz_var(ref); |
463 | | |
464 | 72 | fz_try(ctx) |
465 | 72 | { |
466 | 36 | ref = fz_malloc_array(ctx, vprow, fz_vertex); |
467 | 36 | buf = fz_malloc_array(ctx, vprow, fz_vertex); |
468 | 36 | first = 1; |
469 | | |
470 | 16.9k | while (!fz_is_eof_bits(ctx, stream)) |
471 | 16.9k | { |
472 | 184k | for (i = 0; i < vprow; i++) |
473 | 167k | { |
474 | 167k | x = read_sample(ctx, stream, bpcoord, x0, x1); |
475 | 167k | y = read_sample(ctx, stream, bpcoord, y0, y1); |
476 | 335k | for (k = 0; k < ncomp; k++) |
477 | 168k | c[k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]); |
478 | 167k | fz_prepare_vertex(ctx, painter, &buf[i], ctm, x, y, c); |
479 | 167k | } |
480 | | |
481 | 16.9k | if (!first) |
482 | 166k | for (i = 0; i < vprow - 1; i++) |
483 | 149k | paint_quad(ctx, painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]); |
484 | | |
485 | 16.9k | SWAP(ref,buf); |
486 | 16.9k | first = 0; |
487 | 16.9k | } |
488 | 36 | } |
489 | 72 | fz_always(ctx) |
490 | 36 | { |
491 | 36 | fz_free(ctx, ref); |
492 | 36 | fz_free(ctx, buf); |
493 | 36 | fz_drop_stream(ctx, stream); |
494 | 36 | } |
495 | 36 | fz_catch(ctx) |
496 | 0 | { |
497 | 0 | fz_rethrow(ctx); |
498 | 0 | } |
499 | 36 | } |
500 | | |
501 | | /* Subdivide and tessellate tensor-patches */ |
502 | | |
503 | | typedef struct |
504 | | { |
505 | | fz_point pole[4][4]; |
506 | | float color[4][FZ_MAX_COLORS]; |
507 | | } tensor_patch; |
508 | | |
509 | | static void |
510 | | triangulate_patch(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p) |
511 | 1.23M | { |
512 | 1.23M | fz_vertex v0, v1, v2, v3; |
513 | | |
514 | 1.23M | v0.p = p->pole[0][0]; |
515 | 1.23M | v1.p = p->pole[0][3]; |
516 | 1.23M | v2.p = p->pole[3][3]; |
517 | 1.23M | v3.p = p->pole[3][0]; |
518 | | |
519 | 1.23M | fz_prepare_color(ctx, painter, &v0, p->color[0]); |
520 | 1.23M | fz_prepare_color(ctx, painter, &v1, p->color[1]); |
521 | 1.23M | fz_prepare_color(ctx, painter, &v2, p->color[2]); |
522 | 1.23M | fz_prepare_color(ctx, painter, &v3, p->color[3]); |
523 | | |
524 | 1.23M | paint_quad(ctx, painter, &v0, &v1, &v2, &v3); |
525 | 1.23M | } |
526 | | |
527 | | static inline void midcolor(float *c, float *c1, float *c2, int n) |
528 | 2.42M | { |
529 | 2.42M | int i; |
530 | 10.4M | for (i = 0; i < n; i++) |
531 | 8.03M | c[i] = (c1[i] + c2[i]) * 0.5f; |
532 | 2.42M | } |
533 | | |
534 | | static void |
535 | | split_curve(fz_point *pole, fz_point *q0, fz_point *q1, int polestep) |
536 | 4.84M | { |
537 | | /* |
538 | | split bezier curve given by control points pole[0]..pole[3] |
539 | | using de casteljau algo at midpoint and build two new |
540 | | bezier curves q0[0]..q0[3] and q1[0]..q1[3]. all indices |
541 | | should be multiplies by polestep == 1 for vertical bezier |
542 | | curves in patch and == 4 for horizontal bezier curves due |
543 | | to C's multi-dimensional matrix memory layout. |
544 | | */ |
545 | | |
546 | 4.84M | float x12 = (pole[1 * polestep].x + pole[2 * polestep].x) * 0.5f; |
547 | 4.84M | float y12 = (pole[1 * polestep].y + pole[2 * polestep].y) * 0.5f; |
548 | | |
549 | 4.84M | q0[1 * polestep].x = (pole[0 * polestep].x + pole[1 * polestep].x) * 0.5f; |
550 | 4.84M | q0[1 * polestep].y = (pole[0 * polestep].y + pole[1 * polestep].y) * 0.5f; |
551 | 4.84M | q1[2 * polestep].x = (pole[2 * polestep].x + pole[3 * polestep].x) * 0.5f; |
552 | 4.84M | q1[2 * polestep].y = (pole[2 * polestep].y + pole[3 * polestep].y) * 0.5f; |
553 | | |
554 | 4.84M | q0[2 * polestep].x = (q0[1 * polestep].x + x12) * 0.5f; |
555 | 4.84M | q0[2 * polestep].y = (q0[1 * polestep].y + y12) * 0.5f; |
556 | 4.84M | q1[1 * polestep].x = (x12 + q1[2 * polestep].x) * 0.5f; |
557 | 4.84M | q1[1 * polestep].y = (y12 + q1[2 * polestep].y) * 0.5f; |
558 | | |
559 | 4.84M | q0[3 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f; |
560 | 4.84M | q0[3 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f; |
561 | 4.84M | q1[0 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f; |
562 | 4.84M | q1[0 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f; |
563 | | |
564 | 4.84M | q0[0 * polestep].x = pole[0 * polestep].x; |
565 | 4.84M | q0[0 * polestep].y = pole[0 * polestep].y; |
566 | 4.84M | q1[3 * polestep].x = pole[3 * polestep].x; |
567 | 4.84M | q1[3 * polestep].y = pole[3 * polestep].y; |
568 | 4.84M | } |
569 | | |
570 | | static void |
571 | | split_stripe(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n) |
572 | 1.07M | { |
573 | | /* |
574 | | split all horizontal bezier curves in patch, |
575 | | creating two new patches with half the width. |
576 | | */ |
577 | 1.07M | split_curve(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4); |
578 | 1.07M | split_curve(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4); |
579 | 1.07M | split_curve(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4); |
580 | 1.07M | split_curve(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4); |
581 | | |
582 | | /* interpolate the colors for the two new patches. */ |
583 | 1.07M | memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0])); |
584 | 1.07M | memcpy(s0->color[1], p->color[1], n * sizeof(s0->color[1][0])); |
585 | 1.07M | midcolor(s0->color[2], p->color[1], p->color[2], n); |
586 | 1.07M | midcolor(s0->color[3], p->color[0], p->color[3], n); |
587 | | |
588 | 1.07M | memcpy(s1->color[0], s0->color[3], n * sizeof(s1->color[0][0])); |
589 | 1.07M | memcpy(s1->color[1], s0->color[2], n * sizeof(s1->color[1][0])); |
590 | 1.07M | memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0])); |
591 | 1.07M | memcpy(s1->color[3], p->color[3], n * sizeof(s1->color[3][0])); |
592 | 1.07M | } |
593 | | |
594 | | static void |
595 | | draw_stripe(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth) |
596 | 1.07M | { |
597 | 1.07M | tensor_patch s0, s1; |
598 | | |
599 | | /* split patch into two half-height patches */ |
600 | 1.07M | split_stripe(p, &s0, &s1, painter->ncomp); |
601 | | |
602 | 1.07M | depth--; |
603 | 1.07M | if (depth == 0) |
604 | 615k | { |
605 | | /* if no more subdividing, draw two new patches... */ |
606 | 615k | triangulate_patch(ctx, painter, &s1); |
607 | 615k | triangulate_patch(ctx, painter, &s0); |
608 | 615k | } |
609 | 461k | else |
610 | 461k | { |
611 | | /* ...otherwise, continue subdividing. */ |
612 | 461k | draw_stripe(ctx, painter, &s1, depth); |
613 | 461k | draw_stripe(ctx, painter, &s0, depth); |
614 | 461k | } |
615 | 1.07M | } |
616 | | |
617 | | static void |
618 | | split_patch(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n) |
619 | 134k | { |
620 | | /* |
621 | | split all vertical bezier curves in patch, |
622 | | creating two new patches with half the height. |
623 | | */ |
624 | 134k | split_curve(p->pole[0], s0->pole[0], s1->pole[0], 1); |
625 | 134k | split_curve(p->pole[1], s0->pole[1], s1->pole[1], 1); |
626 | 134k | split_curve(p->pole[2], s0->pole[2], s1->pole[2], 1); |
627 | 134k | split_curve(p->pole[3], s0->pole[3], s1->pole[3], 1); |
628 | | |
629 | | /* interpolate the colors for the two new patches. */ |
630 | 134k | memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0])); |
631 | 134k | midcolor(s0->color[1], p->color[0], p->color[1], n); |
632 | 134k | midcolor(s0->color[2], p->color[2], p->color[3], n); |
633 | 134k | memcpy(s0->color[3], p->color[3], n * sizeof(s0->color[3][0])); |
634 | | |
635 | 134k | memcpy(s1->color[0], s0->color[1], n * sizeof(s1->color[0][0])); |
636 | 134k | memcpy(s1->color[1], p->color[1], n * sizeof(s1->color[1][0])); |
637 | 134k | memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0])); |
638 | 134k | memcpy(s1->color[3], s0->color[2], n * sizeof(s1->color[3][0])); |
639 | 134k | } |
640 | | |
641 | | static void |
642 | | draw_patch(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth, int origdepth) |
643 | 134k | { |
644 | 134k | tensor_patch s0, s1; |
645 | | |
646 | | /* split patch into two half-width patches */ |
647 | 134k | split_patch(p, &s0, &s1, painter->ncomp); |
648 | | |
649 | 134k | depth--; |
650 | 134k | if (depth == 0) |
651 | 76.8k | { |
652 | | /* if no more subdividing, draw two new patches... */ |
653 | 76.8k | draw_stripe(ctx, painter, &s0, origdepth); |
654 | 76.8k | draw_stripe(ctx, painter, &s1, origdepth); |
655 | 76.8k | } |
656 | 57.6k | else |
657 | 57.6k | { |
658 | | /* ...otherwise, continue subdividing. */ |
659 | 57.6k | draw_patch(ctx, painter, &s0, depth, origdepth); |
660 | 57.6k | draw_patch(ctx, painter, &s1, depth, origdepth); |
661 | 57.6k | } |
662 | 134k | } |
663 | | |
664 | | static fz_point |
665 | | compute_tensor_interior( |
666 | | fz_point a, fz_point b, fz_point c, fz_point d, |
667 | | fz_point e, fz_point f, fz_point g, fz_point h) |
668 | 16.7k | { |
669 | 16.7k | fz_point pt; |
670 | | |
671 | | /* see equations at page 330 in pdf 1.7 */ |
672 | | |
673 | 16.7k | pt.x = -4 * a.x; |
674 | 16.7k | pt.x += 6 * (b.x + c.x); |
675 | 16.7k | pt.x += -2 * (d.x + e.x); |
676 | 16.7k | pt.x += 3 * (f.x + g.x); |
677 | 16.7k | pt.x += -1 * h.x; |
678 | 16.7k | pt.x /= 9; |
679 | | |
680 | 16.7k | pt.y = -4 * a.y; |
681 | 16.7k | pt.y += 6 * (b.y + c.y); |
682 | 16.7k | pt.y += -2 * (d.y + e.y); |
683 | 16.7k | pt.y += 3 * (f.y + g.y); |
684 | 16.7k | pt.y += -1 * h.y; |
685 | 16.7k | pt.y /= 9; |
686 | | |
687 | 16.7k | return pt; |
688 | 16.7k | } |
689 | | |
690 | | static void |
691 | | make_tensor_patch(tensor_patch *p, int type, fz_point *pt) |
692 | 19.2k | { |
693 | 19.2k | if (type == 6) |
694 | 4.17k | { |
695 | | /* see control point stream order at page 325 in pdf 1.7 */ |
696 | | |
697 | 4.17k | p->pole[0][0] = pt[0]; |
698 | 4.17k | p->pole[0][1] = pt[1]; |
699 | 4.17k | p->pole[0][2] = pt[2]; |
700 | 4.17k | p->pole[0][3] = pt[3]; |
701 | 4.17k | p->pole[1][3] = pt[4]; |
702 | 4.17k | p->pole[2][3] = pt[5]; |
703 | 4.17k | p->pole[3][3] = pt[6]; |
704 | 4.17k | p->pole[3][2] = pt[7]; |
705 | 4.17k | p->pole[3][1] = pt[8]; |
706 | 4.17k | p->pole[3][0] = pt[9]; |
707 | 4.17k | p->pole[2][0] = pt[10]; |
708 | 4.17k | p->pole[1][0] = pt[11]; |
709 | | |
710 | | /* see equations at page 330 in pdf 1.7 */ |
711 | | |
712 | 4.17k | p->pole[1][1] = compute_tensor_interior( |
713 | 4.17k | p->pole[0][0], p->pole[0][1], p->pole[1][0], p->pole[0][3], |
714 | 4.17k | p->pole[3][0], p->pole[3][1], p->pole[1][3], p->pole[3][3]); |
715 | | |
716 | 4.17k | p->pole[1][2] = compute_tensor_interior( |
717 | 4.17k | p->pole[0][3], p->pole[0][2], p->pole[1][3], p->pole[0][0], |
718 | 4.17k | p->pole[3][3], p->pole[3][2], p->pole[1][0], p->pole[3][0]); |
719 | | |
720 | 4.17k | p->pole[2][1] = compute_tensor_interior( |
721 | 4.17k | p->pole[3][0], p->pole[3][1], p->pole[2][0], p->pole[3][3], |
722 | 4.17k | p->pole[0][0], p->pole[0][1], p->pole[2][3], p->pole[0][3]); |
723 | | |
724 | 4.17k | p->pole[2][2] = compute_tensor_interior( |
725 | 4.17k | p->pole[3][3], p->pole[3][2], p->pole[2][3], p->pole[3][0], |
726 | 4.17k | p->pole[0][3], p->pole[0][2], p->pole[2][0], p->pole[0][0]); |
727 | 4.17k | } |
728 | 15.0k | else if (type == 7) |
729 | 15.0k | { |
730 | | /* see control point stream order at page 330 in pdf 1.7 */ |
731 | | |
732 | 15.0k | p->pole[0][0] = pt[0]; |
733 | 15.0k | p->pole[0][1] = pt[1]; |
734 | 15.0k | p->pole[0][2] = pt[2]; |
735 | 15.0k | p->pole[0][3] = pt[3]; |
736 | 15.0k | p->pole[1][3] = pt[4]; |
737 | 15.0k | p->pole[2][3] = pt[5]; |
738 | 15.0k | p->pole[3][3] = pt[6]; |
739 | 15.0k | p->pole[3][2] = pt[7]; |
740 | 15.0k | p->pole[3][1] = pt[8]; |
741 | 15.0k | p->pole[3][0] = pt[9]; |
742 | 15.0k | p->pole[2][0] = pt[10]; |
743 | 15.0k | p->pole[1][0] = pt[11]; |
744 | 15.0k | p->pole[1][1] = pt[12]; |
745 | 15.0k | p->pole[1][2] = pt[13]; |
746 | 15.0k | p->pole[2][2] = pt[14]; |
747 | 15.0k | p->pole[2][1] = pt[15]; |
748 | 15.0k | } |
749 | 19.2k | } |
750 | | |
751 | | /* FIXME: Nasty */ |
752 | 38.4k | #define SUBDIV 3 /* how many levels to subdivide patches */ |
753 | | |
754 | | static void |
755 | | fz_process_shade_type6(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
756 | 68 | { |
757 | 68 | fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); |
758 | 68 | float color_storage[2][4][FZ_MAX_COLORS]; |
759 | 68 | fz_point point_storage[2][12]; |
760 | 68 | int store = 0; |
761 | 68 | int ncomp = painter->ncomp; |
762 | 68 | int i, k; |
763 | 68 | int bpflag = shade->u.m.bpflag; |
764 | 68 | int bpcoord = shade->u.m.bpcoord; |
765 | 68 | int bpcomp = shade->u.m.bpcomp; |
766 | 68 | float x0 = shade->u.m.x0; |
767 | 68 | float x1 = shade->u.m.x1; |
768 | 68 | float y0 = shade->u.m.y0; |
769 | 68 | float y1 = shade->u.m.y1; |
770 | 68 | const float *c0 = shade->u.m.c0; |
771 | 68 | const float *c1 = shade->u.m.c1; |
772 | | |
773 | 136 | fz_try(ctx) |
774 | 136 | { |
775 | 68 | float (*prevc)[FZ_MAX_COLORS] = NULL; |
776 | 68 | fz_point *prevp = NULL; |
777 | 17.3k | while (!fz_is_eof_bits(ctx, stream)) |
778 | 17.3k | { |
779 | 17.3k | float (*c)[FZ_MAX_COLORS] = color_storage[store]; |
780 | 17.3k | fz_point *v = point_storage[store]; |
781 | 17.3k | int startcolor; |
782 | 17.3k | int startpt; |
783 | 17.3k | int flag; |
784 | 17.3k | tensor_patch patch; |
785 | | |
786 | 17.3k | flag = fz_read_bits(ctx, stream, bpflag); |
787 | | |
788 | 17.3k | if (flag == 0) |
789 | 1.33k | { |
790 | 1.33k | startpt = 0; |
791 | 1.33k | startcolor = 0; |
792 | 1.33k | } |
793 | 15.9k | else |
794 | 15.9k | { |
795 | 15.9k | startpt = 4; |
796 | 15.9k | startcolor = 2; |
797 | 15.9k | } |
798 | | |
799 | 161k | for (i = startpt; i < 12; i++) |
800 | 143k | { |
801 | 143k | v[i].x = read_sample(ctx, stream, bpcoord, x0, x1); |
802 | 143k | v[i].y = read_sample(ctx, stream, bpcoord, y0, y1); |
803 | 143k | v[i] = fz_transform_point(v[i], ctm); |
804 | 143k | } |
805 | | |
806 | 54.6k | for (i = startcolor; i < 4; i++) |
807 | 37.3k | { |
808 | 149k | for (k = 0; k < ncomp; k++) |
809 | 111k | c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]); |
810 | 37.3k | } |
811 | | |
812 | 17.3k | if (flag == 0) |
813 | 1.33k | { |
814 | | /* No patch data to copy forwards */ |
815 | 1.33k | } |
816 | 15.9k | else if (flag == 1 && prevc) |
817 | 511 | { |
818 | 511 | v[0] = prevp[3]; |
819 | 511 | v[1] = prevp[4]; |
820 | 511 | v[2] = prevp[5]; |
821 | 511 | v[3] = prevp[6]; |
822 | 511 | memcpy(c[0], prevc[1], ncomp * sizeof(float)); |
823 | 511 | memcpy(c[1], prevc[2], ncomp * sizeof(float)); |
824 | 511 | } |
825 | 15.4k | else if (flag == 2 && prevc) |
826 | 902 | { |
827 | 902 | v[0] = prevp[6]; |
828 | 902 | v[1] = prevp[7]; |
829 | 902 | v[2] = prevp[8]; |
830 | 902 | v[3] = prevp[9]; |
831 | 902 | memcpy(c[0], prevc[2], ncomp * sizeof(float)); |
832 | 902 | memcpy(c[1], prevc[3], ncomp * sizeof(float)); |
833 | 902 | } |
834 | 14.5k | else if (flag == 3 && prevc) |
835 | 1.42k | { |
836 | 1.42k | v[0] = prevp[ 9]; |
837 | 1.42k | v[1] = prevp[10]; |
838 | 1.42k | v[2] = prevp[11]; |
839 | 1.42k | v[3] = prevp[ 0]; |
840 | 1.42k | memcpy(c[0], prevc[3], ncomp * sizeof(float)); |
841 | 1.42k | memcpy(c[1], prevc[0], ncomp * sizeof(float)); |
842 | 1.42k | } |
843 | 13.1k | else |
844 | 13.1k | continue; |
845 | | |
846 | 4.17k | make_tensor_patch(&patch, 6, v); |
847 | | |
848 | 20.8k | for (i = 0; i < 4; i++) |
849 | 16.7k | memcpy(patch.color[i], c[i], ncomp * sizeof(float)); |
850 | | |
851 | 4.17k | draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV); |
852 | | |
853 | 4.17k | prevp = v; |
854 | 4.17k | prevc = c; |
855 | 4.17k | store ^= 1; |
856 | 4.17k | } |
857 | 68 | } |
858 | 136 | fz_always(ctx) |
859 | 68 | { |
860 | 68 | fz_drop_stream(ctx, stream); |
861 | 68 | } |
862 | 68 | fz_catch(ctx) |
863 | 0 | { |
864 | 0 | fz_rethrow(ctx); |
865 | 0 | } |
866 | 68 | } |
867 | | |
868 | | static void |
869 | | fz_process_shade_type7(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter) |
870 | 247 | { |
871 | 247 | fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer); |
872 | 247 | int bpflag = shade->u.m.bpflag; |
873 | 247 | int bpcoord = shade->u.m.bpcoord; |
874 | 247 | int bpcomp = shade->u.m.bpcomp; |
875 | 247 | float x0 = shade->u.m.x0; |
876 | 247 | float x1 = shade->u.m.x1; |
877 | 247 | float y0 = shade->u.m.y0; |
878 | 247 | float y1 = shade->u.m.y1; |
879 | 247 | const float *c0 = shade->u.m.c0; |
880 | 247 | const float *c1 = shade->u.m.c1; |
881 | 247 | float color_storage[2][4][FZ_MAX_COLORS]; |
882 | 247 | fz_point point_storage[2][16]; |
883 | 247 | int store = 0; |
884 | 247 | int ncomp = painter->ncomp; |
885 | 247 | int i, k; |
886 | 247 | float (*prevc)[FZ_MAX_COLORS] = NULL; |
887 | 247 | fz_point (*prevp) = NULL; |
888 | | |
889 | 494 | fz_try(ctx) |
890 | 494 | { |
891 | 40.2k | while (!fz_is_eof_bits(ctx, stream)) |
892 | 39.9k | { |
893 | 39.9k | float (*c)[FZ_MAX_COLORS] = color_storage[store]; |
894 | 39.9k | fz_point *v = point_storage[store]; |
895 | 39.9k | int startcolor; |
896 | 39.9k | int startpt; |
897 | 39.9k | int flag; |
898 | 39.9k | tensor_patch patch; |
899 | | |
900 | 39.9k | flag = fz_read_bits(ctx, stream, bpflag); |
901 | | |
902 | 39.9k | if (flag == 0) |
903 | 12.1k | { |
904 | 12.1k | startpt = 0; |
905 | 12.1k | startcolor = 0; |
906 | 12.1k | } |
907 | 27.7k | else |
908 | 27.7k | { |
909 | 27.7k | startpt = 4; |
910 | 27.7k | startcolor = 2; |
911 | 27.7k | } |
912 | | |
913 | 568k | for (i = startpt; i < 16; i++) |
914 | 528k | { |
915 | 528k | v[i].x = read_sample(ctx, stream, bpcoord, x0, x1); |
916 | 528k | v[i].y = read_sample(ctx, stream, bpcoord, y0, y1); |
917 | 528k | v[i] = fz_transform_point(v[i], ctm); |
918 | 528k | } |
919 | | |
920 | 144k | for (i = startcolor; i < 4; i++) |
921 | 104k | { |
922 | 442k | for (k = 0; k < ncomp; k++) |
923 | 338k | c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]); |
924 | 104k | } |
925 | | |
926 | 39.9k | if (flag == 0) |
927 | 12.1k | { |
928 | | /* No patch data to copy forward */ |
929 | 12.1k | } |
930 | 27.7k | else if (flag == 1 && prevc) |
931 | 921 | { |
932 | 921 | v[0] = prevp[3]; |
933 | 921 | v[1] = prevp[4]; |
934 | 921 | v[2] = prevp[5]; |
935 | 921 | v[3] = prevp[6]; |
936 | 921 | memcpy(c[0], prevc[1], ncomp * sizeof(float)); |
937 | 921 | memcpy(c[1], prevc[2], ncomp * sizeof(float)); |
938 | 921 | } |
939 | 26.8k | else if (flag == 2 && prevc) |
940 | 880 | { |
941 | 880 | v[0] = prevp[6]; |
942 | 880 | v[1] = prevp[7]; |
943 | 880 | v[2] = prevp[8]; |
944 | 880 | v[3] = prevp[9]; |
945 | 880 | memcpy(c[0], prevc[2], ncomp * sizeof(float)); |
946 | 880 | memcpy(c[1], prevc[3], ncomp * sizeof(float)); |
947 | 880 | } |
948 | 25.9k | else if (flag == 3 && prevc) |
949 | 1.07k | { |
950 | 1.07k | v[0] = prevp[ 9]; |
951 | 1.07k | v[1] = prevp[10]; |
952 | 1.07k | v[2] = prevp[11]; |
953 | 1.07k | v[3] = prevp[ 0]; |
954 | 1.07k | memcpy(c[0], prevc[3], ncomp * sizeof(float)); |
955 | 1.07k | memcpy(c[1], prevc[0], ncomp * sizeof(float)); |
956 | 1.07k | } |
957 | 24.9k | else |
958 | 24.9k | continue; /* We have no patch! */ |
959 | | |
960 | 15.0k | make_tensor_patch(&patch, 7, v); |
961 | | |
962 | 75.2k | for (i = 0; i < 4; i++) |
963 | 60.1k | memcpy(patch.color[i], c[i], ncomp * sizeof(float)); |
964 | | |
965 | 15.0k | draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV); |
966 | | |
967 | 15.0k | prevp = v; |
968 | 15.0k | prevc = c; |
969 | 15.0k | store ^= 1; |
970 | 15.0k | } |
971 | 247 | } |
972 | 494 | fz_always(ctx) |
973 | 247 | { |
974 | 247 | fz_drop_stream(ctx, stream); |
975 | 247 | } |
976 | 247 | fz_catch(ctx) |
977 | 0 | { |
978 | 0 | fz_rethrow(ctx); |
979 | 0 | } |
980 | 247 | } |
981 | | |
982 | | void |
983 | | fz_process_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_rect scissor, |
984 | | fz_shade_prepare_fn *prepare, fz_shade_process_fn *process, void *process_arg) |
985 | 58.3k | { |
986 | 58.3k | fz_mesh_processor painter; |
987 | | |
988 | 58.3k | painter.shade = shade; |
989 | 58.3k | painter.prepare = prepare; |
990 | 58.3k | painter.process = process; |
991 | 58.3k | painter.process_arg = process_arg; |
992 | 58.3k | painter.ncomp = (shade->use_function > 0 ? 1 : fz_colorspace_n(ctx, shade->colorspace)); |
993 | | |
994 | 58.3k | if (shade->type == FZ_FUNCTION_BASED) |
995 | 2 | fz_process_shade_type1(ctx, shade, ctm, &painter); |
996 | 58.3k | else if (shade->type == FZ_LINEAR) |
997 | 57.9k | fz_process_shade_type2(ctx, shade, ctm, &painter, scissor); |
998 | 432 | else if (shade->type == FZ_RADIAL) |
999 | 19 | fz_process_shade_type3(ctx, shade, ctm, &painter); |
1000 | 413 | else if (shade->type == FZ_MESH_TYPE4) |
1001 | 62 | fz_process_shade_type4(ctx, shade, ctm, &painter); |
1002 | 351 | else if (shade->type == FZ_MESH_TYPE5) |
1003 | 36 | fz_process_shade_type5(ctx, shade, ctm, &painter); |
1004 | 315 | else if (shade->type == FZ_MESH_TYPE6) |
1005 | 68 | fz_process_shade_type6(ctx, shade, ctm, &painter); |
1006 | 247 | else if (shade->type == FZ_MESH_TYPE7) |
1007 | 247 | fz_process_shade_type7(ctx, shade, ctm, &painter); |
1008 | 0 | else |
1009 | 0 | fz_throw(ctx, FZ_ERROR_GENERIC, "Unexpected mesh type %d\n", shade->type); |
1010 | 58.3k | } |
1011 | | |
1012 | | static fz_rect |
1013 | | fz_bound_mesh_type1(fz_context *ctx, fz_shade *shade) |
1014 | 4 | { |
1015 | 4 | fz_rect bbox; |
1016 | 4 | bbox.x0 = shade->u.f.domain[0][0]; |
1017 | 4 | bbox.y0 = shade->u.f.domain[0][1]; |
1018 | 4 | bbox.x1 = shade->u.f.domain[1][0]; |
1019 | 4 | bbox.y1 = shade->u.f.domain[1][1]; |
1020 | 4 | return fz_transform_rect(bbox, shade->u.f.matrix); |
1021 | 4 | } |
1022 | | |
1023 | | static fz_rect |
1024 | | fz_bound_mesh_type2(fz_context *ctx, fz_shade *shade) |
1025 | 0 | { |
1026 | | /* FIXME: If axis aligned and not extended, the bbox may only be |
1027 | | * infinite in one direction */ |
1028 | 0 | return fz_infinite_rect; |
1029 | 0 | } |
1030 | | |
1031 | | static fz_rect |
1032 | | fz_bound_mesh_type3(fz_context *ctx, fz_shade *shade) |
1033 | 0 | { |
1034 | 0 | fz_rect bbox; |
1035 | 0 | fz_point p0, p1; |
1036 | 0 | float r0, r1; |
1037 | |
|
1038 | 0 | r0 = shade->u.l_or_r.coords[0][2]; |
1039 | 0 | r1 = shade->u.l_or_r.coords[1][2]; |
1040 | |
|
1041 | 0 | if (shade->u.l_or_r.extend[0]) |
1042 | 0 | { |
1043 | 0 | if (r0 >= r1) |
1044 | 0 | return fz_infinite_rect; |
1045 | 0 | } |
1046 | | |
1047 | 0 | if (shade->u.l_or_r.extend[1]) |
1048 | 0 | { |
1049 | 0 | if (r0 <= r1) |
1050 | 0 | return fz_infinite_rect; |
1051 | 0 | } |
1052 | | |
1053 | 0 | p0.x = shade->u.l_or_r.coords[0][0]; |
1054 | 0 | p0.y = shade->u.l_or_r.coords[0][1]; |
1055 | 0 | p1.x = shade->u.l_or_r.coords[1][0]; |
1056 | 0 | p1.y = shade->u.l_or_r.coords[1][1]; |
1057 | |
|
1058 | 0 | bbox.x0 = p0.x - r0; bbox.y0 = p0.y - r0; |
1059 | 0 | bbox.x1 = p0.x + r0; bbox.y1 = p0.x + r0; |
1060 | 0 | if (bbox.x0 > p1.x - r1) |
1061 | 0 | bbox.x0 = p1.x - r1; |
1062 | 0 | if (bbox.x1 < p1.x + r1) |
1063 | 0 | bbox.x1 = p1.x + r1; |
1064 | 0 | if (bbox.y0 > p1.y - r1) |
1065 | 0 | bbox.y0 = p1.y - r1; |
1066 | 0 | if (bbox.y1 < p1.y + r1) |
1067 | 0 | bbox.y1 = p1.y + r1; |
1068 | 0 | return bbox; |
1069 | 0 | } |
1070 | | |
1071 | | static fz_rect |
1072 | | fz_bound_mesh_type4567(fz_context *ctx, fz_shade *shade) |
1073 | 654 | { |
1074 | 654 | fz_rect bbox; |
1075 | 654 | bbox.x0 = fz_min(shade->u.m.x0, shade->u.m.x1); |
1076 | 654 | bbox.y0 = fz_min(shade->u.m.y0, shade->u.m.y1); |
1077 | 654 | bbox.x1 = fz_max(shade->u.m.x0, shade->u.m.x1); |
1078 | 654 | bbox.y1 = fz_max(shade->u.m.y0, shade->u.m.y1); |
1079 | 654 | return bbox; |
1080 | 654 | } |
1081 | | |
1082 | | static fz_rect |
1083 | | fz_bound_mesh(fz_context *ctx, fz_shade *shade) |
1084 | 658 | { |
1085 | 658 | if (shade->type == FZ_FUNCTION_BASED) |
1086 | 4 | return fz_bound_mesh_type1(ctx, shade); |
1087 | 654 | else if (shade->type == FZ_LINEAR) |
1088 | 0 | return fz_bound_mesh_type2(ctx, shade); |
1089 | 654 | else if (shade->type == FZ_RADIAL) |
1090 | 0 | return fz_bound_mesh_type3(ctx, shade); |
1091 | 654 | else if (shade->type == FZ_MESH_TYPE4 || |
1092 | 654 | shade->type == FZ_MESH_TYPE5 || |
1093 | 654 | shade->type == FZ_MESH_TYPE6 || |
1094 | 654 | shade->type == FZ_MESH_TYPE7) |
1095 | 654 | return fz_bound_mesh_type4567(ctx, shade); |
1096 | 0 | else |
1097 | 0 | fz_throw(ctx, FZ_ERROR_GENERIC, "Unexpected mesh type %d\n", shade->type); |
1098 | 658 | } |
1099 | | |
1100 | | fz_shade * |
1101 | | fz_keep_shade(fz_context *ctx, fz_shade *shade) |
1102 | 5.14k | { |
1103 | 5.14k | return fz_keep_storable(ctx, &shade->storable); |
1104 | 5.14k | } |
1105 | | |
1106 | | void |
1107 | | fz_drop_shade_imp(fz_context *ctx, fz_storable *shade_) |
1108 | 6.85k | { |
1109 | 6.85k | fz_shade *shade = (fz_shade *)shade_; |
1110 | | |
1111 | 6.85k | fz_drop_colorspace(ctx, shade->colorspace); |
1112 | 6.85k | if (shade->type == FZ_FUNCTION_BASED) |
1113 | 2 | fz_free(ctx, shade->u.f.fn_vals); |
1114 | 6.85k | fz_drop_compressed_buffer(ctx, shade->buffer); |
1115 | 6.85k | fz_free(ctx, shade); |
1116 | 6.85k | } |
1117 | | |
1118 | | void |
1119 | | fz_drop_shade(fz_context *ctx, fz_shade *shade) |
1120 | 1.53M | { |
1121 | 1.53M | fz_drop_storable(ctx, &shade->storable); |
1122 | 1.53M | } |
1123 | | |
1124 | | fz_rect |
1125 | | fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm) |
1126 | 123k | { |
1127 | 123k | ctm = fz_concat(shade->matrix, ctm); |
1128 | 123k | if (shade->type != FZ_LINEAR && shade->type != FZ_RADIAL) |
1129 | 658 | { |
1130 | 658 | fz_rect rect = fz_bound_mesh(ctx, shade); |
1131 | 658 | rect = fz_intersect_rect(rect, shade->bbox); |
1132 | 658 | return fz_transform_rect(rect, ctm); |
1133 | 658 | } |
1134 | 122k | return fz_transform_rect(shade->bbox, ctm); |
1135 | 123k | } |