comparison mupdf-source/source/fitz/shade.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 #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 {
42 if (painter->process)
43 {
44 painter->process(ctx, painter->process_arg, v0, v1, v2);
45 }
46 }
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 {
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 if (painter->process)
71 {
72 painter->process(ctx, painter->process_arg, v0, v1, v3);
73 painter->process(ctx, painter->process_arg, v3, v2, v1);
74 }
75 }
76
77 static inline void
78 fz_prepare_color(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v, float *c)
79 {
80 if (painter->prepare)
81 {
82 painter->prepare(ctx, painter->process_arg, v, c);
83 }
84 }
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 {
89 v->p = fz_transform_point_xy(x, y, ctm);
90 if (painter->prepare)
91 {
92 painter->prepare(ctx, painter->process_arg, v, c);
93 }
94 }
95
96 static void
97 fz_process_shade_type1(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
98 {
99 float *p = shade->u.f.fn_vals;
100 int xdivs = shade->u.f.xdivs;
101 int ydivs = shade->u.f.ydivs;
102 float x0 = shade->u.f.domain[0][0];
103 float y0 = shade->u.f.domain[0][1];
104 float x1 = shade->u.f.domain[1][0];
105 float y1 = shade->u.f.domain[1][1];
106 int xx, yy;
107 float y, yn, x;
108 fz_vertex vs[2][2];
109 fz_vertex *v = vs[0];
110 fz_vertex *vn = vs[1];
111 int n = fz_colorspace_n(ctx, shade->colorspace);
112
113 ctm = fz_concat(shade->u.f.matrix, ctm);
114
115 y = y0;
116 for (yy = 0; yy < ydivs; yy++)
117 {
118 yn = y0 + (y1 - y0) * (yy + 1) / ydivs;
119
120 x = x0;
121
122 fz_prepare_vertex(ctx, painter, &v[0], ctm, x, y, p);
123 p += n;
124 fz_prepare_vertex(ctx, painter, &v[1], ctm, x, yn, p + xdivs * n);
125
126 for (xx = 0; xx < xdivs; xx++)
127 {
128 x = x0 + (x1 - x0) * (xx + 1) / xdivs;
129
130 fz_prepare_vertex(ctx, painter, &vn[0], ctm, x, y, p);
131 p += n;
132 fz_prepare_vertex(ctx, painter, &vn[1], ctm, x, yn, p + xdivs * n);
133
134 paint_quad(ctx, painter, &v[0], &vn[0], &vn[1], &v[1]);
135 SWAP(v,vn);
136 }
137 y = yn;
138 }
139 }
140
141 #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 {
146 p.x = p.x + cosf(theta) * r;
147 p.y = p.y + sinf(theta) * r;
148 return p;
149 }
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 {
154 fz_point p0, p1, dir;
155 fz_vertex v0, v1, v2, v3;
156 fz_vertex e0, e1;
157 float theta;
158 float zero = 0;
159 float one = 1;
160 float r;
161
162 p0.x = shade->u.l_or_r.coords[0][0];
163 p0.y = shade->u.l_or_r.coords[0][1];
164 p1.x = shade->u.l_or_r.coords[1][0];
165 p1.y = shade->u.l_or_r.coords[1][1];
166 dir.x = p0.y - p1.y;
167 dir.y = p1.x - p0.x;
168 p0 = fz_transform_point(p0, ctm);
169 p1 = fz_transform_point(p1, ctm);
170 dir = fz_transform_vector(dir, ctm);
171 theta = atan2f(dir.y, dir.x);
172
173 if (fz_is_infinite_rect(scissor)) {
174 r = HUGENUM; /* Not ideal, but it'll do for now */
175 } else {
176 float x = p0.x - scissor.x0;
177 float y = p0.y - scissor.y0;
178 if (x < scissor.x1 - p0.x)
179 x = scissor.x1 - p0.x;
180 if (x < p0.x - scissor.x1)
181 x = p0.x - scissor.x1;
182 if (x < scissor.x1 - p1.x)
183 x = scissor.x1 - p1.x;
184 if (y < scissor.y1 - p0.y)
185 y = scissor.y1 - p0.y;
186 if (y < p0.y - scissor.y1)
187 y = p0.y - scissor.y1;
188 if (y < scissor.y1 - p1.y)
189 y = scissor.y1 - p1.y;
190 r = x+y;
191 }
192 v0.p = fz_point_on_circle(p0, r, theta);
193 v1.p = fz_point_on_circle(p1, r, theta);
194 v2.p.x = 2*p0.x - v0.p.x;
195 v2.p.y = 2*p0.y - v0.p.y;
196 v3.p.x = 2*p1.x - v1.p.x;
197 v3.p.y = 2*p1.y - v1.p.y;
198
199 fz_prepare_color(ctx, painter, &v0, &zero);
200 fz_prepare_color(ctx, painter, &v1, &one);
201 fz_prepare_color(ctx, painter, &v2, &zero);
202 fz_prepare_color(ctx, painter, &v3, &one);
203
204 paint_quad(ctx, painter, &v0, &v2, &v3, &v1);
205
206 if (shade->u.l_or_r.extend[0] || shade->u.l_or_r.extend[1]) {
207 float d = fabsf(p1.x - p0.x);
208 float e = fabsf(p1.y - p0.y);
209 if (d < e)
210 d = e;
211 if (d != 0)
212 r /= d;
213 }
214 if (shade->u.l_or_r.extend[0])
215 {
216 e0.p.x = v0.p.x - (p1.x - p0.x) * r;
217 e0.p.y = v0.p.y - (p1.y - p0.y) * r;
218 fz_prepare_color(ctx, painter, &e0, &zero);
219
220 e1.p.x = v2.p.x - (p1.x - p0.x) * r;
221 e1.p.y = v2.p.y - (p1.y - p0.y) * r;
222 fz_prepare_color(ctx, painter, &e1, &zero);
223
224 paint_quad(ctx, painter, &e0, &v0, &v2, &e1);
225 }
226
227 if (shade->u.l_or_r.extend[1])
228 {
229 e0.p.x = v1.p.x + (p1.x - p0.x) * r;
230 e0.p.y = v1.p.y + (p1.y - p0.y) * r;
231 fz_prepare_color(ctx, painter, &e0, &one);
232
233 e1.p.x = v3.p.x + (p1.x - p0.x) * r;
234 e1.p.y = v3.p.y + (p1.y - p0.y) * r;
235 fz_prepare_color(ctx, painter, &e1, &one);
236
237 paint_quad(ctx, painter, &e0, &v1, &v3, &e1);
238 }
239 }
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 {
248 fz_vertex t0, t1, t2, t3, b0, b1, b2, b3;
249 float theta, step, a, b;
250 int i;
251
252 theta = atan2f(p1.y - p0.y, p1.x - p0.x);
253 step = FZ_PI / count;
254
255 a = 0;
256 for (i = 1; i <= count; i++)
257 {
258 b = i * step;
259
260 t0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + a), ctm);
261 t1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + b), ctm);
262 t2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + a), ctm);
263 t3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + b), ctm);
264 b0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - a), ctm);
265 b1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - b), ctm);
266 b2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - a), ctm);
267 b3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - b), ctm);
268
269 fz_prepare_color(ctx, painter, &t0, &c0);
270 fz_prepare_color(ctx, painter, &t1, &c0);
271 fz_prepare_color(ctx, painter, &t2, &c1);
272 fz_prepare_color(ctx, painter, &t3, &c1);
273 fz_prepare_color(ctx, painter, &b0, &c0);
274 fz_prepare_color(ctx, painter, &b1, &c0);
275 fz_prepare_color(ctx, painter, &b2, &c1);
276 fz_prepare_color(ctx, painter, &b3, &c1);
277
278 paint_quad(ctx, painter, &t0, &t2, &t3, &t1);
279 paint_quad(ctx, painter, &b0, &b2, &b3, &b1);
280
281 a = b;
282 }
283 }
284
285 static void
286 fz_process_shade_type3(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
287 {
288 fz_point p0, p1;
289 float r0, r1;
290 fz_point e;
291 float er, rs;
292 int count;
293
294 p0.x = shade->u.l_or_r.coords[0][0];
295 p0.y = shade->u.l_or_r.coords[0][1];
296 r0 = shade->u.l_or_r.coords[0][2];
297
298 p1.x = shade->u.l_or_r.coords[1][0];
299 p1.y = shade->u.l_or_r.coords[1][1];
300 r1 = shade->u.l_or_r.coords[1][2];
301
302 /* number of segments for a half-circle */
303 count = 4 * sqrtf(fz_matrix_expansion(ctm) * fz_max(r0, r1));
304 if (count < 3)
305 count = 3;
306 if (count > 1024)
307 count = 1024;
308
309 if (shade->u.l_or_r.extend[0])
310 {
311 if (r0 < r1)
312 rs = r0 / (r0 - r1);
313 else
314 rs = -HUGENUM;
315
316 e.x = p0.x + (p1.x - p0.x) * rs;
317 e.y = p0.y + (p1.y - p0.y) * rs;
318 er = r0 + (r1 - r0) * rs;
319
320 fz_paint_annulus(ctx, ctm, e, er, 0, p0, r0, 0, count, painter);
321 }
322
323 fz_paint_annulus(ctx, ctm, p0, r0, 0, p1, r1, 1, count, painter);
324
325 if (shade->u.l_or_r.extend[1])
326 {
327 if (r0 > r1)
328 rs = r1 / (r1 - r0);
329 else
330 rs = -HUGENUM;
331
332 e.x = p1.x + (p0.x - p1.x) * rs;
333 e.y = p1.y + (p0.y - p1.y) * rs;
334 er = r1 + (r0 - r1) * rs;
335
336 fz_paint_annulus(ctx, ctm, p1, r1, 1, e, er, 1, count, painter);
337 }
338 }
339
340 static inline float read_sample(fz_context *ctx, fz_stream *stream, int bits, float min, float max)
341 {
342 /* we use pow(2,x) because (1<<x) would overflow the math on 32-bit samples */
343 float bitscale = 1 / (powf(2, bits) - 1);
344 return min + fz_read_bits(ctx, stream, bits) * (max - min) * bitscale;
345 }
346
347 static void
348 fz_process_shade_type4(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
349 {
350 fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
351 fz_vertex v[4];
352 fz_vertex *va = &v[0];
353 fz_vertex *vb = &v[1];
354 fz_vertex *vc = &v[2];
355 fz_vertex *vd = &v[3];
356 int flag, i, ncomp = painter->ncomp;
357 int bpflag = shade->u.m.bpflag;
358 int bpcoord = shade->u.m.bpcoord;
359 int bpcomp = shade->u.m.bpcomp;
360 float x0 = shade->u.m.x0;
361 float x1 = shade->u.m.x1;
362 float y0 = shade->u.m.y0;
363 float y1 = shade->u.m.y1;
364 const float *c0 = shade->u.m.c0;
365 const float *c1 = shade->u.m.c1;
366 float x, y, c[FZ_MAX_COLORS];
367 int first_triangle = 1;
368
369 fz_try(ctx)
370 {
371 while (!fz_is_eof_bits(ctx, stream))
372 {
373 flag = fz_read_bits(ctx, stream, bpflag);
374 x = read_sample(ctx, stream, bpcoord, x0, x1);
375 y = read_sample(ctx, stream, bpcoord, y0, y1);
376 for (i = 0; i < ncomp; i++)
377 c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
378 fz_prepare_vertex(ctx, painter, vd, ctm, x, y, c);
379
380 if (first_triangle)
381 {
382 if (flag != 0)
383 {
384 fz_warn(ctx, "ignoring non-zero edge flags for first vertex in mesh");
385 flag = 0;
386 }
387 first_triangle = 0;
388 }
389
390 switch (flag)
391 {
392 default:
393 fz_warn(ctx, "ignoring out of range edge flag in mesh");
394 /* fallthrough */
395
396 case 0: /* start new triangle */
397 SWAP(va, vd);
398
399 fz_read_bits(ctx, stream, bpflag);
400 x = read_sample(ctx, stream, bpcoord, x0, x1);
401 y = read_sample(ctx, stream, bpcoord, y0, y1);
402 for (i = 0; i < ncomp; i++)
403 c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
404 fz_prepare_vertex(ctx, painter, vb, ctm, x, y, c);
405
406 fz_read_bits(ctx, stream, bpflag);
407 x = read_sample(ctx, stream, bpcoord, x0, x1);
408 y = read_sample(ctx, stream, bpcoord, y0, y1);
409 for (i = 0; i < ncomp; i++)
410 c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
411 fz_prepare_vertex(ctx, painter, vc, ctm, x, y, c);
412
413 paint_tri(ctx, painter, va, vb, vc);
414 break;
415
416 case 1: /* Vb, Vc, Vd */
417 SWAP(va, vb);
418 SWAP(vb, vc);
419 SWAP(vc, vd);
420 paint_tri(ctx, painter, va, vb, vc);
421 break;
422
423 case 2: /* Va, Vc, Vd */
424 SWAP(vb, vc);
425 SWAP(vc, vd);
426 paint_tri(ctx, painter, va, vb, vc);
427 break;
428 }
429 }
430 }
431 fz_always(ctx)
432 {
433 fz_drop_stream(ctx, stream);
434 }
435 fz_catch(ctx)
436 {
437 fz_rethrow(ctx);
438 }
439 }
440
441 static void
442 fz_process_shade_type5(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
443 {
444 fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
445 fz_vertex *buf = NULL;
446 fz_vertex *ref = NULL;
447 int first;
448 int ncomp = painter->ncomp;
449 int i, k;
450 int vprow = shade->u.m.vprow;
451 int bpcoord = shade->u.m.bpcoord;
452 int bpcomp = shade->u.m.bpcomp;
453 float x0 = shade->u.m.x0;
454 float x1 = shade->u.m.x1;
455 float y0 = shade->u.m.y0;
456 float y1 = shade->u.m.y1;
457 const float *c0 = shade->u.m.c0;
458 const float *c1 = shade->u.m.c1;
459 float x, y, c[FZ_MAX_COLORS];
460
461 fz_var(buf);
462 fz_var(ref);
463
464 fz_try(ctx)
465 {
466 ref = fz_malloc_array(ctx, vprow, fz_vertex);
467 buf = fz_malloc_array(ctx, vprow, fz_vertex);
468 first = 1;
469
470 while (!fz_is_eof_bits(ctx, stream))
471 {
472 for (i = 0; i < vprow; i++)
473 {
474 x = read_sample(ctx, stream, bpcoord, x0, x1);
475 y = read_sample(ctx, stream, bpcoord, y0, y1);
476 for (k = 0; k < ncomp; k++)
477 c[k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
478 fz_prepare_vertex(ctx, painter, &buf[i], ctm, x, y, c);
479 }
480
481 if (!first)
482 for (i = 0; i < vprow - 1; i++)
483 paint_quad(ctx, painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]);
484
485 SWAP(ref,buf);
486 first = 0;
487 }
488 }
489 fz_always(ctx)
490 {
491 fz_free(ctx, ref);
492 fz_free(ctx, buf);
493 fz_drop_stream(ctx, stream);
494 }
495 fz_catch(ctx)
496 {
497 fz_rethrow(ctx);
498 }
499 }
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 {
512 fz_vertex v0, v1, v2, v3;
513
514 v0.p = p->pole[0][0];
515 v1.p = p->pole[0][3];
516 v2.p = p->pole[3][3];
517 v3.p = p->pole[3][0];
518
519 fz_prepare_color(ctx, painter, &v0, p->color[0]);
520 fz_prepare_color(ctx, painter, &v1, p->color[1]);
521 fz_prepare_color(ctx, painter, &v2, p->color[2]);
522 fz_prepare_color(ctx, painter, &v3, p->color[3]);
523
524 paint_quad(ctx, painter, &v0, &v1, &v2, &v3);
525 }
526
527 static inline void midcolor(float *c, float *c1, float *c2, int n)
528 {
529 int i;
530 for (i = 0; i < n; i++)
531 c[i] = (c1[i] + c2[i]) * 0.5f;
532 }
533
534 static void
535 split_curve(fz_point *pole, fz_point *q0, fz_point *q1, int polestep)
536 {
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 float x12 = (pole[1 * polestep].x + pole[2 * polestep].x) * 0.5f;
547 float y12 = (pole[1 * polestep].y + pole[2 * polestep].y) * 0.5f;
548
549 q0[1 * polestep].x = (pole[0 * polestep].x + pole[1 * polestep].x) * 0.5f;
550 q0[1 * polestep].y = (pole[0 * polestep].y + pole[1 * polestep].y) * 0.5f;
551 q1[2 * polestep].x = (pole[2 * polestep].x + pole[3 * polestep].x) * 0.5f;
552 q1[2 * polestep].y = (pole[2 * polestep].y + pole[3 * polestep].y) * 0.5f;
553
554 q0[2 * polestep].x = (q0[1 * polestep].x + x12) * 0.5f;
555 q0[2 * polestep].y = (q0[1 * polestep].y + y12) * 0.5f;
556 q1[1 * polestep].x = (x12 + q1[2 * polestep].x) * 0.5f;
557 q1[1 * polestep].y = (y12 + q1[2 * polestep].y) * 0.5f;
558
559 q0[3 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f;
560 q0[3 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f;
561 q1[0 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f;
562 q1[0 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f;
563
564 q0[0 * polestep].x = pole[0 * polestep].x;
565 q0[0 * polestep].y = pole[0 * polestep].y;
566 q1[3 * polestep].x = pole[3 * polestep].x;
567 q1[3 * polestep].y = pole[3 * polestep].y;
568 }
569
570 static void
571 split_stripe(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n)
572 {
573 /*
574 split all horizontal bezier curves in patch,
575 creating two new patches with half the width.
576 */
577 split_curve(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4);
578 split_curve(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4);
579 split_curve(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4);
580 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 memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0]));
584 memcpy(s0->color[1], p->color[1], n * sizeof(s0->color[1][0]));
585 midcolor(s0->color[2], p->color[1], p->color[2], n);
586 midcolor(s0->color[3], p->color[0], p->color[3], n);
587
588 memcpy(s1->color[0], s0->color[3], n * sizeof(s1->color[0][0]));
589 memcpy(s1->color[1], s0->color[2], n * sizeof(s1->color[1][0]));
590 memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0]));
591 memcpy(s1->color[3], p->color[3], n * sizeof(s1->color[3][0]));
592 }
593
594 static void
595 draw_stripe(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth)
596 {
597 tensor_patch s0, s1;
598
599 /* split patch into two half-height patches */
600 split_stripe(p, &s0, &s1, painter->ncomp);
601
602 depth--;
603 if (depth == 0)
604 {
605 /* if no more subdividing, draw two new patches... */
606 triangulate_patch(ctx, painter, &s1);
607 triangulate_patch(ctx, painter, &s0);
608 }
609 else
610 {
611 /* ...otherwise, continue subdividing. */
612 draw_stripe(ctx, painter, &s1, depth);
613 draw_stripe(ctx, painter, &s0, depth);
614 }
615 }
616
617 static void
618 split_patch(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n)
619 {
620 /*
621 split all vertical bezier curves in patch,
622 creating two new patches with half the height.
623 */
624 split_curve(p->pole[0], s0->pole[0], s1->pole[0], 1);
625 split_curve(p->pole[1], s0->pole[1], s1->pole[1], 1);
626 split_curve(p->pole[2], s0->pole[2], s1->pole[2], 1);
627 split_curve(p->pole[3], s0->pole[3], s1->pole[3], 1);
628
629 /* interpolate the colors for the two new patches. */
630 memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0]));
631 midcolor(s0->color[1], p->color[0], p->color[1], n);
632 midcolor(s0->color[2], p->color[2], p->color[3], n);
633 memcpy(s0->color[3], p->color[3], n * sizeof(s0->color[3][0]));
634
635 memcpy(s1->color[0], s0->color[1], n * sizeof(s1->color[0][0]));
636 memcpy(s1->color[1], p->color[1], n * sizeof(s1->color[1][0]));
637 memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0]));
638 memcpy(s1->color[3], s0->color[2], n * sizeof(s1->color[3][0]));
639 }
640
641 static void
642 draw_patch(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth, int origdepth)
643 {
644 tensor_patch s0, s1;
645
646 /* split patch into two half-width patches */
647 split_patch(p, &s0, &s1, painter->ncomp);
648
649 depth--;
650 if (depth == 0)
651 {
652 /* if no more subdividing, draw two new patches... */
653 draw_stripe(ctx, painter, &s0, origdepth);
654 draw_stripe(ctx, painter, &s1, origdepth);
655 }
656 else
657 {
658 /* ...otherwise, continue subdividing. */
659 draw_patch(ctx, painter, &s0, depth, origdepth);
660 draw_patch(ctx, painter, &s1, depth, origdepth);
661 }
662 }
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 {
669 fz_point pt;
670
671 /* see equations at page 330 in pdf 1.7 */
672
673 pt.x = -4 * a.x;
674 pt.x += 6 * (b.x + c.x);
675 pt.x += -2 * (d.x + e.x);
676 pt.x += 3 * (f.x + g.x);
677 pt.x += -1 * h.x;
678 pt.x /= 9;
679
680 pt.y = -4 * a.y;
681 pt.y += 6 * (b.y + c.y);
682 pt.y += -2 * (d.y + e.y);
683 pt.y += 3 * (f.y + g.y);
684 pt.y += -1 * h.y;
685 pt.y /= 9;
686
687 return pt;
688 }
689
690 static void
691 make_tensor_patch(tensor_patch *p, int type, fz_point *pt)
692 {
693 if (type == 6)
694 {
695 /* see control point stream order at page 325 in pdf 1.7 */
696
697 p->pole[0][0] = pt[0];
698 p->pole[0][1] = pt[1];
699 p->pole[0][2] = pt[2];
700 p->pole[0][3] = pt[3];
701 p->pole[1][3] = pt[4];
702 p->pole[2][3] = pt[5];
703 p->pole[3][3] = pt[6];
704 p->pole[3][2] = pt[7];
705 p->pole[3][1] = pt[8];
706 p->pole[3][0] = pt[9];
707 p->pole[2][0] = pt[10];
708 p->pole[1][0] = pt[11];
709
710 /* see equations at page 330 in pdf 1.7 */
711
712 p->pole[1][1] = compute_tensor_interior(
713 p->pole[0][0], p->pole[0][1], p->pole[1][0], p->pole[0][3],
714 p->pole[3][0], p->pole[3][1], p->pole[1][3], p->pole[3][3]);
715
716 p->pole[1][2] = compute_tensor_interior(
717 p->pole[0][3], p->pole[0][2], p->pole[1][3], p->pole[0][0],
718 p->pole[3][3], p->pole[3][2], p->pole[1][0], p->pole[3][0]);
719
720 p->pole[2][1] = compute_tensor_interior(
721 p->pole[3][0], p->pole[3][1], p->pole[2][0], p->pole[3][3],
722 p->pole[0][0], p->pole[0][1], p->pole[2][3], p->pole[0][3]);
723
724 p->pole[2][2] = compute_tensor_interior(
725 p->pole[3][3], p->pole[3][2], p->pole[2][3], p->pole[3][0],
726 p->pole[0][3], p->pole[0][2], p->pole[2][0], p->pole[0][0]);
727 }
728 else if (type == 7)
729 {
730 /* see control point stream order at page 330 in pdf 1.7 */
731
732 p->pole[0][0] = pt[0];
733 p->pole[0][1] = pt[1];
734 p->pole[0][2] = pt[2];
735 p->pole[0][3] = pt[3];
736 p->pole[1][3] = pt[4];
737 p->pole[2][3] = pt[5];
738 p->pole[3][3] = pt[6];
739 p->pole[3][2] = pt[7];
740 p->pole[3][1] = pt[8];
741 p->pole[3][0] = pt[9];
742 p->pole[2][0] = pt[10];
743 p->pole[1][0] = pt[11];
744 p->pole[1][1] = pt[12];
745 p->pole[1][2] = pt[13];
746 p->pole[2][2] = pt[14];
747 p->pole[2][1] = pt[15];
748 }
749 }
750
751 /* FIXME: Nasty */
752 #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 {
757 fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
758 float color_storage[2][4][FZ_MAX_COLORS];
759 fz_point point_storage[2][12];
760 int store = 0;
761 int ncomp = painter->ncomp;
762 int i, k;
763 int bpflag = shade->u.m.bpflag;
764 int bpcoord = shade->u.m.bpcoord;
765 int bpcomp = shade->u.m.bpcomp;
766 float x0 = shade->u.m.x0;
767 float x1 = shade->u.m.x1;
768 float y0 = shade->u.m.y0;
769 float y1 = shade->u.m.y1;
770 const float *c0 = shade->u.m.c0;
771 const float *c1 = shade->u.m.c1;
772
773 fz_try(ctx)
774 {
775 float (*prevc)[FZ_MAX_COLORS] = NULL;
776 fz_point *prevp = NULL;
777 while (!fz_is_eof_bits(ctx, stream))
778 {
779 float (*c)[FZ_MAX_COLORS] = color_storage[store];
780 fz_point *v = point_storage[store];
781 int startcolor;
782 int startpt;
783 int flag;
784 tensor_patch patch;
785
786 flag = fz_read_bits(ctx, stream, bpflag);
787
788 if (flag == 0)
789 {
790 startpt = 0;
791 startcolor = 0;
792 }
793 else
794 {
795 startpt = 4;
796 startcolor = 2;
797 }
798
799 for (i = startpt; i < 12; i++)
800 {
801 v[i].x = read_sample(ctx, stream, bpcoord, x0, x1);
802 v[i].y = read_sample(ctx, stream, bpcoord, y0, y1);
803 v[i] = fz_transform_point(v[i], ctm);
804 }
805
806 for (i = startcolor; i < 4; i++)
807 {
808 for (k = 0; k < ncomp; k++)
809 c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
810 }
811
812 if (flag == 0)
813 {
814 /* No patch data to copy forwards */
815 }
816 else if (flag == 1 && prevc)
817 {
818 v[0] = prevp[3];
819 v[1] = prevp[4];
820 v[2] = prevp[5];
821 v[3] = prevp[6];
822 memcpy(c[0], prevc[1], ncomp * sizeof(float));
823 memcpy(c[1], prevc[2], ncomp * sizeof(float));
824 }
825 else if (flag == 2 && prevc)
826 {
827 v[0] = prevp[6];
828 v[1] = prevp[7];
829 v[2] = prevp[8];
830 v[3] = prevp[9];
831 memcpy(c[0], prevc[2], ncomp * sizeof(float));
832 memcpy(c[1], prevc[3], ncomp * sizeof(float));
833 }
834 else if (flag == 3 && prevc)
835 {
836 v[0] = prevp[ 9];
837 v[1] = prevp[10];
838 v[2] = prevp[11];
839 v[3] = prevp[ 0];
840 memcpy(c[0], prevc[3], ncomp * sizeof(float));
841 memcpy(c[1], prevc[0], ncomp * sizeof(float));
842 }
843 else
844 continue;
845
846 make_tensor_patch(&patch, 6, v);
847
848 for (i = 0; i < 4; i++)
849 memcpy(patch.color[i], c[i], ncomp * sizeof(float));
850
851 draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV);
852
853 prevp = v;
854 prevc = c;
855 store ^= 1;
856 }
857 }
858 fz_always(ctx)
859 {
860 fz_drop_stream(ctx, stream);
861 }
862 fz_catch(ctx)
863 {
864 fz_rethrow(ctx);
865 }
866 }
867
868 static void
869 fz_process_shade_type7(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
870 {
871 fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
872 int bpflag = shade->u.m.bpflag;
873 int bpcoord = shade->u.m.bpcoord;
874 int bpcomp = shade->u.m.bpcomp;
875 float x0 = shade->u.m.x0;
876 float x1 = shade->u.m.x1;
877 float y0 = shade->u.m.y0;
878 float y1 = shade->u.m.y1;
879 const float *c0 = shade->u.m.c0;
880 const float *c1 = shade->u.m.c1;
881 float color_storage[2][4][FZ_MAX_COLORS];
882 fz_point point_storage[2][16];
883 int store = 0;
884 int ncomp = painter->ncomp;
885 int i, k;
886 float (*prevc)[FZ_MAX_COLORS] = NULL;
887 fz_point (*prevp) = NULL;
888
889 fz_try(ctx)
890 {
891 while (!fz_is_eof_bits(ctx, stream))
892 {
893 float (*c)[FZ_MAX_COLORS] = color_storage[store];
894 fz_point *v = point_storage[store];
895 int startcolor;
896 int startpt;
897 int flag;
898 tensor_patch patch;
899
900 flag = fz_read_bits(ctx, stream, bpflag);
901
902 if (flag == 0)
903 {
904 startpt = 0;
905 startcolor = 0;
906 }
907 else
908 {
909 startpt = 4;
910 startcolor = 2;
911 }
912
913 for (i = startpt; i < 16; i++)
914 {
915 v[i].x = read_sample(ctx, stream, bpcoord, x0, x1);
916 v[i].y = read_sample(ctx, stream, bpcoord, y0, y1);
917 v[i] = fz_transform_point(v[i], ctm);
918 }
919
920 for (i = startcolor; i < 4; i++)
921 {
922 for (k = 0; k < ncomp; k++)
923 c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
924 }
925
926 if (flag == 0)
927 {
928 /* No patch data to copy forward */
929 }
930 else if (flag == 1 && prevc)
931 {
932 v[0] = prevp[3];
933 v[1] = prevp[4];
934 v[2] = prevp[5];
935 v[3] = prevp[6];
936 memcpy(c[0], prevc[1], ncomp * sizeof(float));
937 memcpy(c[1], prevc[2], ncomp * sizeof(float));
938 }
939 else if (flag == 2 && prevc)
940 {
941 v[0] = prevp[6];
942 v[1] = prevp[7];
943 v[2] = prevp[8];
944 v[3] = prevp[9];
945 memcpy(c[0], prevc[2], ncomp * sizeof(float));
946 memcpy(c[1], prevc[3], ncomp * sizeof(float));
947 }
948 else if (flag == 3 && prevc)
949 {
950 v[0] = prevp[ 9];
951 v[1] = prevp[10];
952 v[2] = prevp[11];
953 v[3] = prevp[ 0];
954 memcpy(c[0], prevc[3], ncomp * sizeof(float));
955 memcpy(c[1], prevc[0], ncomp * sizeof(float));
956 }
957 else
958 continue; /* We have no patch! */
959
960 make_tensor_patch(&patch, 7, v);
961
962 for (i = 0; i < 4; i++)
963 memcpy(patch.color[i], c[i], ncomp * sizeof(float));
964
965 draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV);
966
967 prevp = v;
968 prevc = c;
969 store ^= 1;
970 }
971 }
972 fz_always(ctx)
973 {
974 fz_drop_stream(ctx, stream);
975 }
976 fz_catch(ctx)
977 {
978 fz_rethrow(ctx);
979 }
980 }
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 {
986 fz_mesh_processor painter;
987
988 painter.shade = shade;
989 painter.prepare = prepare;
990 painter.process = process;
991 painter.process_arg = process_arg;
992 painter.ncomp = (shade->function_stride > 0 ? 1 : fz_colorspace_n(ctx, shade->colorspace));
993
994 if (shade->type == FZ_FUNCTION_BASED)
995 fz_process_shade_type1(ctx, shade, ctm, &painter);
996 else if (shade->type == FZ_LINEAR)
997 fz_process_shade_type2(ctx, shade, ctm, &painter, scissor);
998 else if (shade->type == FZ_RADIAL)
999 fz_process_shade_type3(ctx, shade, ctm, &painter);
1000 else if (shade->type == FZ_MESH_TYPE4)
1001 fz_process_shade_type4(ctx, shade, ctm, &painter);
1002 else if (shade->type == FZ_MESH_TYPE5)
1003 fz_process_shade_type5(ctx, shade, ctm, &painter);
1004 else if (shade->type == FZ_MESH_TYPE6)
1005 fz_process_shade_type6(ctx, shade, ctm, &painter);
1006 else if (shade->type == FZ_MESH_TYPE7)
1007 fz_process_shade_type7(ctx, shade, ctm, &painter);
1008 else
1009 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unexpected mesh type %d\n", shade->type);
1010 }
1011
1012 static fz_rect
1013 fz_bound_mesh_type1(fz_context *ctx, fz_shade *shade)
1014 {
1015 fz_rect bbox;
1016 bbox.x0 = shade->u.f.domain[0][0];
1017 bbox.y0 = shade->u.f.domain[0][1];
1018 bbox.x1 = shade->u.f.domain[1][0];
1019 bbox.y1 = shade->u.f.domain[1][1];
1020 return fz_transform_rect(bbox, shade->u.f.matrix);
1021 }
1022
1023 static fz_rect
1024 fz_bound_mesh_type2(fz_context *ctx, fz_shade *shade)
1025 {
1026 /* FIXME: If axis aligned and not extended, the bbox may only be
1027 * infinite in one direction */
1028 return fz_infinite_rect;
1029 }
1030
1031 static fz_rect
1032 fz_bound_mesh_type3(fz_context *ctx, fz_shade *shade)
1033 {
1034 fz_rect bbox;
1035 fz_point p0, p1;
1036 float r0, r1;
1037
1038 r0 = shade->u.l_or_r.coords[0][2];
1039 r1 = shade->u.l_or_r.coords[1][2];
1040
1041 if (shade->u.l_or_r.extend[0])
1042 {
1043 if (r0 >= r1)
1044 return fz_infinite_rect;
1045 }
1046
1047 if (shade->u.l_or_r.extend[1])
1048 {
1049 if (r0 <= r1)
1050 return fz_infinite_rect;
1051 }
1052
1053 p0.x = shade->u.l_or_r.coords[0][0];
1054 p0.y = shade->u.l_or_r.coords[0][1];
1055 p1.x = shade->u.l_or_r.coords[1][0];
1056 p1.y = shade->u.l_or_r.coords[1][1];
1057
1058 bbox.x0 = p0.x - r0; bbox.y0 = p0.y - r0;
1059 bbox.x1 = p0.x + r0; bbox.y1 = p0.x + r0;
1060 if (bbox.x0 > p1.x - r1)
1061 bbox.x0 = p1.x - r1;
1062 if (bbox.x1 < p1.x + r1)
1063 bbox.x1 = p1.x + r1;
1064 if (bbox.y0 > p1.y - r1)
1065 bbox.y0 = p1.y - r1;
1066 if (bbox.y1 < p1.y + r1)
1067 bbox.y1 = p1.y + r1;
1068 return bbox;
1069 }
1070
1071 static fz_rect
1072 fz_bound_mesh_type4567(fz_context *ctx, fz_shade *shade)
1073 {
1074 fz_rect bbox;
1075 bbox.x0 = fz_min(shade->u.m.x0, shade->u.m.x1);
1076 bbox.y0 = fz_min(shade->u.m.y0, shade->u.m.y1);
1077 bbox.x1 = fz_max(shade->u.m.x0, shade->u.m.x1);
1078 bbox.y1 = fz_max(shade->u.m.y0, shade->u.m.y1);
1079 return bbox;
1080 }
1081
1082 static fz_rect
1083 fz_bound_mesh(fz_context *ctx, fz_shade *shade)
1084 {
1085 if (shade->type == FZ_FUNCTION_BASED)
1086 return fz_bound_mesh_type1(ctx, shade);
1087 else if (shade->type == FZ_LINEAR)
1088 return fz_bound_mesh_type2(ctx, shade);
1089 else if (shade->type == FZ_RADIAL)
1090 return fz_bound_mesh_type3(ctx, shade);
1091 else if (shade->type == FZ_MESH_TYPE4 ||
1092 shade->type == FZ_MESH_TYPE5 ||
1093 shade->type == FZ_MESH_TYPE6 ||
1094 shade->type == FZ_MESH_TYPE7)
1095 return fz_bound_mesh_type4567(ctx, shade);
1096 else
1097 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unexpected mesh type %d\n", shade->type);
1098 }
1099
1100 fz_shade *
1101 fz_keep_shade(fz_context *ctx, fz_shade *shade)
1102 {
1103 return fz_keep_storable(ctx, &shade->storable);
1104 }
1105
1106 void
1107 fz_drop_shade_imp(fz_context *ctx, fz_storable *shade_)
1108 {
1109 fz_shade *shade = (fz_shade *)shade_;
1110
1111 fz_drop_colorspace(ctx, shade->colorspace);
1112 if (shade->type == FZ_FUNCTION_BASED)
1113 fz_free(ctx, shade->u.f.fn_vals);
1114 fz_drop_compressed_buffer(ctx, shade->buffer);
1115 fz_free(ctx, shade->function);
1116 fz_free(ctx, shade);
1117 }
1118
1119 void
1120 fz_drop_shade(fz_context *ctx, fz_shade *shade)
1121 {
1122 fz_drop_storable(ctx, &shade->storable);
1123 }
1124
1125 fz_rect
1126 fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm)
1127 {
1128 ctm = fz_concat(shade->matrix, ctm);
1129 if (shade->type != FZ_LINEAR && shade->type != FZ_RADIAL)
1130 {
1131 fz_rect rect = fz_bound_mesh(ctx, shade);
1132 rect = fz_intersect_rect(rect, shade->bbox);
1133 return fz_transform_rect(rect, ctm);
1134 }
1135 return fz_transform_rect(shade->bbox, ctm);
1136 }