| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136 |
- // Copyright (C) 2004-2021 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include <string.h>
- #include <math.h>
- typedef struct
- {
- fz_shade *shade;
- fz_shade_prepare_fn *prepare;
- fz_shade_process_fn *process;
- void *process_arg;
- int ncomp;
- } fz_mesh_processor;
- #define SWAP(a,b) {fz_vertex *t = (a); (a) = (b); (b) = t;}
- static inline void
- paint_tri(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2)
- {
- if (painter->process)
- {
- painter->process(ctx, painter->process_arg, v0, v1, v2);
- }
- }
- static inline void
- paint_quad(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v0, fz_vertex *v1, fz_vertex *v2, fz_vertex *v3)
- {
- /* For a quad with corners (in clockwise or anticlockwise order) are
- * v0, v1, v2, v3. We can choose to split in in various different ways.
- * Arbitrarily we can pick v0, v1, v3 for the first triangle. We then
- * have to choose between v1, v2, v3 or v3, v2, v1 (or their equivalent
- * rotations) for the second triangle.
- *
- * v1, v2, v3 has the property that both triangles share the same
- * winding (useful if we were ever doing simple back face culling).
- *
- * v3, v2, v1 has the property that all the 'shared' edges (both
- * within this quad, and with adjacent quads) are walked in the same
- * direction every time. This can be useful in that depending on the
- * implementation/rounding etc walking from A -> B can hit different
- * pixels than walking from B->A.
- *
- * In the event neither of these things matter at the moment, as all
- * the process functions where it matters order the edges from top to
- * bottom before walking them.
- */
- if (painter->process)
- {
- painter->process(ctx, painter->process_arg, v0, v1, v3);
- painter->process(ctx, painter->process_arg, v3, v2, v1);
- }
- }
- static inline void
- fz_prepare_color(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v, float *c)
- {
- if (painter->prepare)
- {
- painter->prepare(ctx, painter->process_arg, v, c);
- }
- }
- static inline void
- fz_prepare_vertex(fz_context *ctx, fz_mesh_processor *painter, fz_vertex *v, fz_matrix ctm, float x, float y, float *c)
- {
- v->p = fz_transform_point_xy(x, y, ctm);
- if (painter->prepare)
- {
- painter->prepare(ctx, painter->process_arg, v, c);
- }
- }
- static void
- fz_process_shade_type1(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- float *p = shade->u.f.fn_vals;
- int xdivs = shade->u.f.xdivs;
- int ydivs = shade->u.f.ydivs;
- float x0 = shade->u.f.domain[0][0];
- float y0 = shade->u.f.domain[0][1];
- float x1 = shade->u.f.domain[1][0];
- float y1 = shade->u.f.domain[1][1];
- int xx, yy;
- float y, yn, x;
- fz_vertex vs[2][2];
- fz_vertex *v = vs[0];
- fz_vertex *vn = vs[1];
- int n = fz_colorspace_n(ctx, shade->colorspace);
- ctm = fz_concat(shade->u.f.matrix, ctm);
- y = y0;
- for (yy = 0; yy < ydivs; yy++)
- {
- yn = y0 + (y1 - y0) * (yy + 1) / ydivs;
- x = x0;
- fz_prepare_vertex(ctx, painter, &v[0], ctm, x, y, p);
- p += n;
- fz_prepare_vertex(ctx, painter, &v[1], ctm, x, yn, p + xdivs * n);
- for (xx = 0; xx < xdivs; xx++)
- {
- x = x0 + (x1 - x0) * (xx + 1) / xdivs;
- fz_prepare_vertex(ctx, painter, &vn[0], ctm, x, y, p);
- p += n;
- fz_prepare_vertex(ctx, painter, &vn[1], ctm, x, yn, p + xdivs * n);
- paint_quad(ctx, painter, &v[0], &vn[0], &vn[1], &v[1]);
- SWAP(v,vn);
- }
- y = yn;
- }
- }
- #define HUGENUM 32000 /* how far to extend linear/radial shadings */
- static fz_point
- fz_point_on_circle(fz_point p, float r, float theta)
- {
- p.x = p.x + cosf(theta) * r;
- p.y = p.y + sinf(theta) * r;
- return p;
- }
- static void
- fz_process_shade_type2(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter, fz_rect scissor)
- {
- fz_point p0, p1, dir;
- fz_vertex v0, v1, v2, v3;
- fz_vertex e0, e1;
- float theta;
- float zero = 0;
- float one = 1;
- float r;
- p0.x = shade->u.l_or_r.coords[0][0];
- p0.y = shade->u.l_or_r.coords[0][1];
- p1.x = shade->u.l_or_r.coords[1][0];
- p1.y = shade->u.l_or_r.coords[1][1];
- dir.x = p0.y - p1.y;
- dir.y = p1.x - p0.x;
- p0 = fz_transform_point(p0, ctm);
- p1 = fz_transform_point(p1, ctm);
- dir = fz_transform_vector(dir, ctm);
- theta = atan2f(dir.y, dir.x);
- if (fz_is_infinite_rect(scissor)) {
- r = HUGENUM; /* Not ideal, but it'll do for now */
- } else {
- float x = p0.x - scissor.x0;
- float y = p0.y - scissor.y0;
- if (x < scissor.x1 - p0.x)
- x = scissor.x1 - p0.x;
- if (x < p0.x - scissor.x1)
- x = p0.x - scissor.x1;
- if (x < scissor.x1 - p1.x)
- x = scissor.x1 - p1.x;
- if (y < scissor.y1 - p0.y)
- y = scissor.y1 - p0.y;
- if (y < p0.y - scissor.y1)
- y = p0.y - scissor.y1;
- if (y < scissor.y1 - p1.y)
- y = scissor.y1 - p1.y;
- r = x+y;
- }
- v0.p = fz_point_on_circle(p0, r, theta);
- v1.p = fz_point_on_circle(p1, r, theta);
- v2.p.x = 2*p0.x - v0.p.x;
- v2.p.y = 2*p0.y - v0.p.y;
- v3.p.x = 2*p1.x - v1.p.x;
- v3.p.y = 2*p1.y - v1.p.y;
- fz_prepare_color(ctx, painter, &v0, &zero);
- fz_prepare_color(ctx, painter, &v1, &one);
- fz_prepare_color(ctx, painter, &v2, &zero);
- fz_prepare_color(ctx, painter, &v3, &one);
- paint_quad(ctx, painter, &v0, &v2, &v3, &v1);
- if (shade->u.l_or_r.extend[0] || shade->u.l_or_r.extend[1]) {
- float d = fabsf(p1.x - p0.x);
- float e = fabsf(p1.y - p0.y);
- if (d < e)
- d = e;
- if (d != 0)
- r /= d;
- }
- if (shade->u.l_or_r.extend[0])
- {
- e0.p.x = v0.p.x - (p1.x - p0.x) * r;
- e0.p.y = v0.p.y - (p1.y - p0.y) * r;
- fz_prepare_color(ctx, painter, &e0, &zero);
- e1.p.x = v2.p.x - (p1.x - p0.x) * r;
- e1.p.y = v2.p.y - (p1.y - p0.y) * r;
- fz_prepare_color(ctx, painter, &e1, &zero);
- paint_quad(ctx, painter, &e0, &v0, &v2, &e1);
- }
- if (shade->u.l_or_r.extend[1])
- {
- e0.p.x = v1.p.x + (p1.x - p0.x) * r;
- e0.p.y = v1.p.y + (p1.y - p0.y) * r;
- fz_prepare_color(ctx, painter, &e0, &one);
- e1.p.x = v3.p.x + (p1.x - p0.x) * r;
- e1.p.y = v3.p.y + (p1.y - p0.y) * r;
- fz_prepare_color(ctx, painter, &e1, &one);
- paint_quad(ctx, painter, &e0, &v1, &v3, &e1);
- }
- }
- static void
- fz_paint_annulus(fz_context *ctx, fz_matrix ctm,
- fz_point p0, float r0, float c0,
- fz_point p1, float r1, float c1,
- int count,
- fz_mesh_processor *painter)
- {
- fz_vertex t0, t1, t2, t3, b0, b1, b2, b3;
- float theta, step, a, b;
- int i;
- theta = atan2f(p1.y - p0.y, p1.x - p0.x);
- step = FZ_PI / count;
- a = 0;
- for (i = 1; i <= count; i++)
- {
- b = i * step;
- t0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + a), ctm);
- t1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta + b), ctm);
- t2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + a), ctm);
- t3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta + b), ctm);
- b0.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - a), ctm);
- b1.p = fz_transform_point(fz_point_on_circle(p0, r0, theta - b), ctm);
- b2.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - a), ctm);
- b3.p = fz_transform_point(fz_point_on_circle(p1, r1, theta - b), ctm);
- fz_prepare_color(ctx, painter, &t0, &c0);
- fz_prepare_color(ctx, painter, &t1, &c0);
- fz_prepare_color(ctx, painter, &t2, &c1);
- fz_prepare_color(ctx, painter, &t3, &c1);
- fz_prepare_color(ctx, painter, &b0, &c0);
- fz_prepare_color(ctx, painter, &b1, &c0);
- fz_prepare_color(ctx, painter, &b2, &c1);
- fz_prepare_color(ctx, painter, &b3, &c1);
- paint_quad(ctx, painter, &t0, &t2, &t3, &t1);
- paint_quad(ctx, painter, &b0, &b2, &b3, &b1);
- a = b;
- }
- }
- static void
- fz_process_shade_type3(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- fz_point p0, p1;
- float r0, r1;
- fz_point e;
- float er, rs;
- int count;
- p0.x = shade->u.l_or_r.coords[0][0];
- p0.y = shade->u.l_or_r.coords[0][1];
- r0 = shade->u.l_or_r.coords[0][2];
- p1.x = shade->u.l_or_r.coords[1][0];
- p1.y = shade->u.l_or_r.coords[1][1];
- r1 = shade->u.l_or_r.coords[1][2];
- /* number of segments for a half-circle */
- count = 4 * sqrtf(fz_matrix_expansion(ctm) * fz_max(r0, r1));
- if (count < 3)
- count = 3;
- if (count > 1024)
- count = 1024;
- if (shade->u.l_or_r.extend[0])
- {
- if (r0 < r1)
- rs = r0 / (r0 - r1);
- else
- rs = -HUGENUM;
- e.x = p0.x + (p1.x - p0.x) * rs;
- e.y = p0.y + (p1.y - p0.y) * rs;
- er = r0 + (r1 - r0) * rs;
- fz_paint_annulus(ctx, ctm, e, er, 0, p0, r0, 0, count, painter);
- }
- fz_paint_annulus(ctx, ctm, p0, r0, 0, p1, r1, 1, count, painter);
- if (shade->u.l_or_r.extend[1])
- {
- if (r0 > r1)
- rs = r1 / (r1 - r0);
- else
- rs = -HUGENUM;
- e.x = p1.x + (p0.x - p1.x) * rs;
- e.y = p1.y + (p0.y - p1.y) * rs;
- er = r1 + (r0 - r1) * rs;
- fz_paint_annulus(ctx, ctm, p1, r1, 1, e, er, 1, count, painter);
- }
- }
- static inline float read_sample(fz_context *ctx, fz_stream *stream, int bits, float min, float max)
- {
- /* we use pow(2,x) because (1<<x) would overflow the math on 32-bit samples */
- float bitscale = 1 / (powf(2, bits) - 1);
- return min + fz_read_bits(ctx, stream, bits) * (max - min) * bitscale;
- }
- static void
- fz_process_shade_type4(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
- fz_vertex v[4];
- fz_vertex *va = &v[0];
- fz_vertex *vb = &v[1];
- fz_vertex *vc = &v[2];
- fz_vertex *vd = &v[3];
- int flag, i, ncomp = painter->ncomp;
- int bpflag = shade->u.m.bpflag;
- int bpcoord = shade->u.m.bpcoord;
- int bpcomp = shade->u.m.bpcomp;
- float x0 = shade->u.m.x0;
- float x1 = shade->u.m.x1;
- float y0 = shade->u.m.y0;
- float y1 = shade->u.m.y1;
- const float *c0 = shade->u.m.c0;
- const float *c1 = shade->u.m.c1;
- float x, y, c[FZ_MAX_COLORS];
- int first_triangle = 1;
- fz_try(ctx)
- {
- while (!fz_is_eof_bits(ctx, stream))
- {
- flag = fz_read_bits(ctx, stream, bpflag);
- x = read_sample(ctx, stream, bpcoord, x0, x1);
- y = read_sample(ctx, stream, bpcoord, y0, y1);
- for (i = 0; i < ncomp; i++)
- c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
- fz_prepare_vertex(ctx, painter, vd, ctm, x, y, c);
- if (first_triangle)
- {
- if (flag != 0)
- {
- fz_warn(ctx, "ignoring non-zero edge flags for first vertex in mesh");
- flag = 0;
- }
- first_triangle = 0;
- }
- switch (flag)
- {
- default:
- fz_warn(ctx, "ignoring out of range edge flag in mesh");
- /* fallthrough */
- case 0: /* start new triangle */
- SWAP(va, vd);
- fz_read_bits(ctx, stream, bpflag);
- x = read_sample(ctx, stream, bpcoord, x0, x1);
- y = read_sample(ctx, stream, bpcoord, y0, y1);
- for (i = 0; i < ncomp; i++)
- c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
- fz_prepare_vertex(ctx, painter, vb, ctm, x, y, c);
- fz_read_bits(ctx, stream, bpflag);
- x = read_sample(ctx, stream, bpcoord, x0, x1);
- y = read_sample(ctx, stream, bpcoord, y0, y1);
- for (i = 0; i < ncomp; i++)
- c[i] = read_sample(ctx, stream, bpcomp, c0[i], c1[i]);
- fz_prepare_vertex(ctx, painter, vc, ctm, x, y, c);
- paint_tri(ctx, painter, va, vb, vc);
- break;
- case 1: /* Vb, Vc, Vd */
- SWAP(va, vb);
- SWAP(vb, vc);
- SWAP(vc, vd);
- paint_tri(ctx, painter, va, vb, vc);
- break;
- case 2: /* Va, Vc, Vd */
- SWAP(vb, vc);
- SWAP(vc, vd);
- paint_tri(ctx, painter, va, vb, vc);
- break;
- }
- }
- }
- fz_always(ctx)
- {
- fz_drop_stream(ctx, stream);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
- static void
- fz_process_shade_type5(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
- fz_vertex *buf = NULL;
- fz_vertex *ref = NULL;
- int first;
- int ncomp = painter->ncomp;
- int i, k;
- int vprow = shade->u.m.vprow;
- int bpcoord = shade->u.m.bpcoord;
- int bpcomp = shade->u.m.bpcomp;
- float x0 = shade->u.m.x0;
- float x1 = shade->u.m.x1;
- float y0 = shade->u.m.y0;
- float y1 = shade->u.m.y1;
- const float *c0 = shade->u.m.c0;
- const float *c1 = shade->u.m.c1;
- float x, y, c[FZ_MAX_COLORS];
- fz_var(buf);
- fz_var(ref);
- fz_try(ctx)
- {
- ref = fz_malloc_array(ctx, vprow, fz_vertex);
- buf = fz_malloc_array(ctx, vprow, fz_vertex);
- first = 1;
- while (!fz_is_eof_bits(ctx, stream))
- {
- for (i = 0; i < vprow; i++)
- {
- x = read_sample(ctx, stream, bpcoord, x0, x1);
- y = read_sample(ctx, stream, bpcoord, y0, y1);
- for (k = 0; k < ncomp; k++)
- c[k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
- fz_prepare_vertex(ctx, painter, &buf[i], ctm, x, y, c);
- }
- if (!first)
- for (i = 0; i < vprow - 1; i++)
- paint_quad(ctx, painter, &ref[i], &ref[i+1], &buf[i+1], &buf[i]);
- SWAP(ref,buf);
- first = 0;
- }
- }
- fz_always(ctx)
- {
- fz_free(ctx, ref);
- fz_free(ctx, buf);
- fz_drop_stream(ctx, stream);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
- /* Subdivide and tessellate tensor-patches */
- typedef struct
- {
- fz_point pole[4][4];
- float color[4][FZ_MAX_COLORS];
- } tensor_patch;
- static void
- triangulate_patch(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p)
- {
- fz_vertex v0, v1, v2, v3;
- v0.p = p->pole[0][0];
- v1.p = p->pole[0][3];
- v2.p = p->pole[3][3];
- v3.p = p->pole[3][0];
- fz_prepare_color(ctx, painter, &v0, p->color[0]);
- fz_prepare_color(ctx, painter, &v1, p->color[1]);
- fz_prepare_color(ctx, painter, &v2, p->color[2]);
- fz_prepare_color(ctx, painter, &v3, p->color[3]);
- paint_quad(ctx, painter, &v0, &v1, &v2, &v3);
- }
- static inline void midcolor(float *c, float *c1, float *c2, int n)
- {
- int i;
- for (i = 0; i < n; i++)
- c[i] = (c1[i] + c2[i]) * 0.5f;
- }
- static void
- split_curve(fz_point *pole, fz_point *q0, fz_point *q1, int polestep)
- {
- /*
- split bezier curve given by control points pole[0]..pole[3]
- using de casteljau algo at midpoint and build two new
- bezier curves q0[0]..q0[3] and q1[0]..q1[3]. all indices
- should be multiplies by polestep == 1 for vertical bezier
- curves in patch and == 4 for horizontal bezier curves due
- to C's multi-dimensional matrix memory layout.
- */
- float x12 = (pole[1 * polestep].x + pole[2 * polestep].x) * 0.5f;
- float y12 = (pole[1 * polestep].y + pole[2 * polestep].y) * 0.5f;
- q0[1 * polestep].x = (pole[0 * polestep].x + pole[1 * polestep].x) * 0.5f;
- q0[1 * polestep].y = (pole[0 * polestep].y + pole[1 * polestep].y) * 0.5f;
- q1[2 * polestep].x = (pole[2 * polestep].x + pole[3 * polestep].x) * 0.5f;
- q1[2 * polestep].y = (pole[2 * polestep].y + pole[3 * polestep].y) * 0.5f;
- q0[2 * polestep].x = (q0[1 * polestep].x + x12) * 0.5f;
- q0[2 * polestep].y = (q0[1 * polestep].y + y12) * 0.5f;
- q1[1 * polestep].x = (x12 + q1[2 * polestep].x) * 0.5f;
- q1[1 * polestep].y = (y12 + q1[2 * polestep].y) * 0.5f;
- q0[3 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f;
- q0[3 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f;
- q1[0 * polestep].x = (q0[2 * polestep].x + q1[1 * polestep].x) * 0.5f;
- q1[0 * polestep].y = (q0[2 * polestep].y + q1[1 * polestep].y) * 0.5f;
- q0[0 * polestep].x = pole[0 * polestep].x;
- q0[0 * polestep].y = pole[0 * polestep].y;
- q1[3 * polestep].x = pole[3 * polestep].x;
- q1[3 * polestep].y = pole[3 * polestep].y;
- }
- static void
- split_stripe(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n)
- {
- /*
- split all horizontal bezier curves in patch,
- creating two new patches with half the width.
- */
- split_curve(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4);
- split_curve(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4);
- split_curve(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4);
- split_curve(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4);
- /* interpolate the colors for the two new patches. */
- memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0]));
- memcpy(s0->color[1], p->color[1], n * sizeof(s0->color[1][0]));
- midcolor(s0->color[2], p->color[1], p->color[2], n);
- midcolor(s0->color[3], p->color[0], p->color[3], n);
- memcpy(s1->color[0], s0->color[3], n * sizeof(s1->color[0][0]));
- memcpy(s1->color[1], s0->color[2], n * sizeof(s1->color[1][0]));
- memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0]));
- memcpy(s1->color[3], p->color[3], n * sizeof(s1->color[3][0]));
- }
- static void
- draw_stripe(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth)
- {
- tensor_patch s0, s1;
- /* split patch into two half-height patches */
- split_stripe(p, &s0, &s1, painter->ncomp);
- depth--;
- if (depth == 0)
- {
- /* if no more subdividing, draw two new patches... */
- triangulate_patch(ctx, painter, &s1);
- triangulate_patch(ctx, painter, &s0);
- }
- else
- {
- /* ...otherwise, continue subdividing. */
- draw_stripe(ctx, painter, &s1, depth);
- draw_stripe(ctx, painter, &s0, depth);
- }
- }
- static void
- split_patch(tensor_patch *p, tensor_patch *s0, tensor_patch *s1, int n)
- {
- /*
- split all vertical bezier curves in patch,
- creating two new patches with half the height.
- */
- split_curve(p->pole[0], s0->pole[0], s1->pole[0], 1);
- split_curve(p->pole[1], s0->pole[1], s1->pole[1], 1);
- split_curve(p->pole[2], s0->pole[2], s1->pole[2], 1);
- split_curve(p->pole[3], s0->pole[3], s1->pole[3], 1);
- /* interpolate the colors for the two new patches. */
- memcpy(s0->color[0], p->color[0], n * sizeof(s0->color[0][0]));
- midcolor(s0->color[1], p->color[0], p->color[1], n);
- midcolor(s0->color[2], p->color[2], p->color[3], n);
- memcpy(s0->color[3], p->color[3], n * sizeof(s0->color[3][0]));
- memcpy(s1->color[0], s0->color[1], n * sizeof(s1->color[0][0]));
- memcpy(s1->color[1], p->color[1], n * sizeof(s1->color[1][0]));
- memcpy(s1->color[2], p->color[2], n * sizeof(s1->color[2][0]));
- memcpy(s1->color[3], s0->color[2], n * sizeof(s1->color[3][0]));
- }
- static void
- draw_patch(fz_context *ctx, fz_mesh_processor *painter, tensor_patch *p, int depth, int origdepth)
- {
- tensor_patch s0, s1;
- /* split patch into two half-width patches */
- split_patch(p, &s0, &s1, painter->ncomp);
- depth--;
- if (depth == 0)
- {
- /* if no more subdividing, draw two new patches... */
- draw_stripe(ctx, painter, &s0, origdepth);
- draw_stripe(ctx, painter, &s1, origdepth);
- }
- else
- {
- /* ...otherwise, continue subdividing. */
- draw_patch(ctx, painter, &s0, depth, origdepth);
- draw_patch(ctx, painter, &s1, depth, origdepth);
- }
- }
- static fz_point
- compute_tensor_interior(
- fz_point a, fz_point b, fz_point c, fz_point d,
- fz_point e, fz_point f, fz_point g, fz_point h)
- {
- fz_point pt;
- /* see equations at page 330 in pdf 1.7 */
- pt.x = -4 * a.x;
- pt.x += 6 * (b.x + c.x);
- pt.x += -2 * (d.x + e.x);
- pt.x += 3 * (f.x + g.x);
- pt.x += -1 * h.x;
- pt.x /= 9;
- pt.y = -4 * a.y;
- pt.y += 6 * (b.y + c.y);
- pt.y += -2 * (d.y + e.y);
- pt.y += 3 * (f.y + g.y);
- pt.y += -1 * h.y;
- pt.y /= 9;
- return pt;
- }
- static void
- make_tensor_patch(tensor_patch *p, int type, fz_point *pt)
- {
- if (type == 6)
- {
- /* see control point stream order at page 325 in pdf 1.7 */
- p->pole[0][0] = pt[0];
- p->pole[0][1] = pt[1];
- p->pole[0][2] = pt[2];
- p->pole[0][3] = pt[3];
- p->pole[1][3] = pt[4];
- p->pole[2][3] = pt[5];
- p->pole[3][3] = pt[6];
- p->pole[3][2] = pt[7];
- p->pole[3][1] = pt[8];
- p->pole[3][0] = pt[9];
- p->pole[2][0] = pt[10];
- p->pole[1][0] = pt[11];
- /* see equations at page 330 in pdf 1.7 */
- p->pole[1][1] = compute_tensor_interior(
- p->pole[0][0], p->pole[0][1], p->pole[1][0], p->pole[0][3],
- p->pole[3][0], p->pole[3][1], p->pole[1][3], p->pole[3][3]);
- p->pole[1][2] = compute_tensor_interior(
- p->pole[0][3], p->pole[0][2], p->pole[1][3], p->pole[0][0],
- p->pole[3][3], p->pole[3][2], p->pole[1][0], p->pole[3][0]);
- p->pole[2][1] = compute_tensor_interior(
- p->pole[3][0], p->pole[3][1], p->pole[2][0], p->pole[3][3],
- p->pole[0][0], p->pole[0][1], p->pole[2][3], p->pole[0][3]);
- p->pole[2][2] = compute_tensor_interior(
- p->pole[3][3], p->pole[3][2], p->pole[2][3], p->pole[3][0],
- p->pole[0][3], p->pole[0][2], p->pole[2][0], p->pole[0][0]);
- }
- else if (type == 7)
- {
- /* see control point stream order at page 330 in pdf 1.7 */
- p->pole[0][0] = pt[0];
- p->pole[0][1] = pt[1];
- p->pole[0][2] = pt[2];
- p->pole[0][3] = pt[3];
- p->pole[1][3] = pt[4];
- p->pole[2][3] = pt[5];
- p->pole[3][3] = pt[6];
- p->pole[3][2] = pt[7];
- p->pole[3][1] = pt[8];
- p->pole[3][0] = pt[9];
- p->pole[2][0] = pt[10];
- p->pole[1][0] = pt[11];
- p->pole[1][1] = pt[12];
- p->pole[1][2] = pt[13];
- p->pole[2][2] = pt[14];
- p->pole[2][1] = pt[15];
- }
- }
- /* FIXME: Nasty */
- #define SUBDIV 3 /* how many levels to subdivide patches */
- static void
- fz_process_shade_type6(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
- float color_storage[2][4][FZ_MAX_COLORS];
- fz_point point_storage[2][12];
- int store = 0;
- int ncomp = painter->ncomp;
- int i, k;
- int bpflag = shade->u.m.bpflag;
- int bpcoord = shade->u.m.bpcoord;
- int bpcomp = shade->u.m.bpcomp;
- float x0 = shade->u.m.x0;
- float x1 = shade->u.m.x1;
- float y0 = shade->u.m.y0;
- float y1 = shade->u.m.y1;
- const float *c0 = shade->u.m.c0;
- const float *c1 = shade->u.m.c1;
- fz_try(ctx)
- {
- float (*prevc)[FZ_MAX_COLORS] = NULL;
- fz_point *prevp = NULL;
- while (!fz_is_eof_bits(ctx, stream))
- {
- float (*c)[FZ_MAX_COLORS] = color_storage[store];
- fz_point *v = point_storage[store];
- int startcolor;
- int startpt;
- int flag;
- tensor_patch patch;
- flag = fz_read_bits(ctx, stream, bpflag);
- if (flag == 0)
- {
- startpt = 0;
- startcolor = 0;
- }
- else
- {
- startpt = 4;
- startcolor = 2;
- }
- for (i = startpt; i < 12; i++)
- {
- v[i].x = read_sample(ctx, stream, bpcoord, x0, x1);
- v[i].y = read_sample(ctx, stream, bpcoord, y0, y1);
- v[i] = fz_transform_point(v[i], ctm);
- }
- for (i = startcolor; i < 4; i++)
- {
- for (k = 0; k < ncomp; k++)
- c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
- }
- if (flag == 0)
- {
- /* No patch data to copy forwards */
- }
- else if (flag == 1 && prevc)
- {
- v[0] = prevp[3];
- v[1] = prevp[4];
- v[2] = prevp[5];
- v[3] = prevp[6];
- memcpy(c[0], prevc[1], ncomp * sizeof(float));
- memcpy(c[1], prevc[2], ncomp * sizeof(float));
- }
- else if (flag == 2 && prevc)
- {
- v[0] = prevp[6];
- v[1] = prevp[7];
- v[2] = prevp[8];
- v[3] = prevp[9];
- memcpy(c[0], prevc[2], ncomp * sizeof(float));
- memcpy(c[1], prevc[3], ncomp * sizeof(float));
- }
- else if (flag == 3 && prevc)
- {
- v[0] = prevp[ 9];
- v[1] = prevp[10];
- v[2] = prevp[11];
- v[3] = prevp[ 0];
- memcpy(c[0], prevc[3], ncomp * sizeof(float));
- memcpy(c[1], prevc[0], ncomp * sizeof(float));
- }
- else
- continue;
- make_tensor_patch(&patch, 6, v);
- for (i = 0; i < 4; i++)
- memcpy(patch.color[i], c[i], ncomp * sizeof(float));
- draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV);
- prevp = v;
- prevc = c;
- store ^= 1;
- }
- }
- fz_always(ctx)
- {
- fz_drop_stream(ctx, stream);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
- static void
- fz_process_shade_type7(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_mesh_processor *painter)
- {
- fz_stream *stream = fz_open_compressed_buffer(ctx, shade->buffer);
- int bpflag = shade->u.m.bpflag;
- int bpcoord = shade->u.m.bpcoord;
- int bpcomp = shade->u.m.bpcomp;
- float x0 = shade->u.m.x0;
- float x1 = shade->u.m.x1;
- float y0 = shade->u.m.y0;
- float y1 = shade->u.m.y1;
- const float *c0 = shade->u.m.c0;
- const float *c1 = shade->u.m.c1;
- float color_storage[2][4][FZ_MAX_COLORS];
- fz_point point_storage[2][16];
- int store = 0;
- int ncomp = painter->ncomp;
- int i, k;
- float (*prevc)[FZ_MAX_COLORS] = NULL;
- fz_point (*prevp) = NULL;
- fz_try(ctx)
- {
- while (!fz_is_eof_bits(ctx, stream))
- {
- float (*c)[FZ_MAX_COLORS] = color_storage[store];
- fz_point *v = point_storage[store];
- int startcolor;
- int startpt;
- int flag;
- tensor_patch patch;
- flag = fz_read_bits(ctx, stream, bpflag);
- if (flag == 0)
- {
- startpt = 0;
- startcolor = 0;
- }
- else
- {
- startpt = 4;
- startcolor = 2;
- }
- for (i = startpt; i < 16; i++)
- {
- v[i].x = read_sample(ctx, stream, bpcoord, x0, x1);
- v[i].y = read_sample(ctx, stream, bpcoord, y0, y1);
- v[i] = fz_transform_point(v[i], ctm);
- }
- for (i = startcolor; i < 4; i++)
- {
- for (k = 0; k < ncomp; k++)
- c[i][k] = read_sample(ctx, stream, bpcomp, c0[k], c1[k]);
- }
- if (flag == 0)
- {
- /* No patch data to copy forward */
- }
- else if (flag == 1 && prevc)
- {
- v[0] = prevp[3];
- v[1] = prevp[4];
- v[2] = prevp[5];
- v[3] = prevp[6];
- memcpy(c[0], prevc[1], ncomp * sizeof(float));
- memcpy(c[1], prevc[2], ncomp * sizeof(float));
- }
- else if (flag == 2 && prevc)
- {
- v[0] = prevp[6];
- v[1] = prevp[7];
- v[2] = prevp[8];
- v[3] = prevp[9];
- memcpy(c[0], prevc[2], ncomp * sizeof(float));
- memcpy(c[1], prevc[3], ncomp * sizeof(float));
- }
- else if (flag == 3 && prevc)
- {
- v[0] = prevp[ 9];
- v[1] = prevp[10];
- v[2] = prevp[11];
- v[3] = prevp[ 0];
- memcpy(c[0], prevc[3], ncomp * sizeof(float));
- memcpy(c[1], prevc[0], ncomp * sizeof(float));
- }
- else
- continue; /* We have no patch! */
- make_tensor_patch(&patch, 7, v);
- for (i = 0; i < 4; i++)
- memcpy(patch.color[i], c[i], ncomp * sizeof(float));
- draw_patch(ctx, painter, &patch, SUBDIV, SUBDIV);
- prevp = v;
- prevc = c;
- store ^= 1;
- }
- }
- fz_always(ctx)
- {
- fz_drop_stream(ctx, stream);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- }
- void
- fz_process_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_rect scissor,
- fz_shade_prepare_fn *prepare, fz_shade_process_fn *process, void *process_arg)
- {
- fz_mesh_processor painter;
- painter.shade = shade;
- painter.prepare = prepare;
- painter.process = process;
- painter.process_arg = process_arg;
- painter.ncomp = (shade->function_stride > 0 ? 1 : fz_colorspace_n(ctx, shade->colorspace));
- if (shade->type == FZ_FUNCTION_BASED)
- fz_process_shade_type1(ctx, shade, ctm, &painter);
- else if (shade->type == FZ_LINEAR)
- fz_process_shade_type2(ctx, shade, ctm, &painter, scissor);
- else if (shade->type == FZ_RADIAL)
- fz_process_shade_type3(ctx, shade, ctm, &painter);
- else if (shade->type == FZ_MESH_TYPE4)
- fz_process_shade_type4(ctx, shade, ctm, &painter);
- else if (shade->type == FZ_MESH_TYPE5)
- fz_process_shade_type5(ctx, shade, ctm, &painter);
- else if (shade->type == FZ_MESH_TYPE6)
- fz_process_shade_type6(ctx, shade, ctm, &painter);
- else if (shade->type == FZ_MESH_TYPE7)
- fz_process_shade_type7(ctx, shade, ctm, &painter);
- else
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unexpected mesh type %d\n", shade->type);
- }
- static fz_rect
- fz_bound_mesh_type1(fz_context *ctx, fz_shade *shade)
- {
- fz_rect bbox;
- bbox.x0 = shade->u.f.domain[0][0];
- bbox.y0 = shade->u.f.domain[0][1];
- bbox.x1 = shade->u.f.domain[1][0];
- bbox.y1 = shade->u.f.domain[1][1];
- return fz_transform_rect(bbox, shade->u.f.matrix);
- }
- static fz_rect
- fz_bound_mesh_type2(fz_context *ctx, fz_shade *shade)
- {
- /* FIXME: If axis aligned and not extended, the bbox may only be
- * infinite in one direction */
- return fz_infinite_rect;
- }
- static fz_rect
- fz_bound_mesh_type3(fz_context *ctx, fz_shade *shade)
- {
- fz_rect bbox;
- fz_point p0, p1;
- float r0, r1;
- r0 = shade->u.l_or_r.coords[0][2];
- r1 = shade->u.l_or_r.coords[1][2];
- if (shade->u.l_or_r.extend[0])
- {
- if (r0 >= r1)
- return fz_infinite_rect;
- }
- if (shade->u.l_or_r.extend[1])
- {
- if (r0 <= r1)
- return fz_infinite_rect;
- }
- p0.x = shade->u.l_or_r.coords[0][0];
- p0.y = shade->u.l_or_r.coords[0][1];
- p1.x = shade->u.l_or_r.coords[1][0];
- p1.y = shade->u.l_or_r.coords[1][1];
- bbox.x0 = p0.x - r0; bbox.y0 = p0.y - r0;
- bbox.x1 = p0.x + r0; bbox.y1 = p0.x + r0;
- if (bbox.x0 > p1.x - r1)
- bbox.x0 = p1.x - r1;
- if (bbox.x1 < p1.x + r1)
- bbox.x1 = p1.x + r1;
- if (bbox.y0 > p1.y - r1)
- bbox.y0 = p1.y - r1;
- if (bbox.y1 < p1.y + r1)
- bbox.y1 = p1.y + r1;
- return bbox;
- }
- static fz_rect
- fz_bound_mesh_type4567(fz_context *ctx, fz_shade *shade)
- {
- fz_rect bbox;
- bbox.x0 = fz_min(shade->u.m.x0, shade->u.m.x1);
- bbox.y0 = fz_min(shade->u.m.y0, shade->u.m.y1);
- bbox.x1 = fz_max(shade->u.m.x0, shade->u.m.x1);
- bbox.y1 = fz_max(shade->u.m.y0, shade->u.m.y1);
- return bbox;
- }
- static fz_rect
- fz_bound_mesh(fz_context *ctx, fz_shade *shade)
- {
- if (shade->type == FZ_FUNCTION_BASED)
- return fz_bound_mesh_type1(ctx, shade);
- else if (shade->type == FZ_LINEAR)
- return fz_bound_mesh_type2(ctx, shade);
- else if (shade->type == FZ_RADIAL)
- return fz_bound_mesh_type3(ctx, shade);
- else if (shade->type == FZ_MESH_TYPE4 ||
- shade->type == FZ_MESH_TYPE5 ||
- shade->type == FZ_MESH_TYPE6 ||
- shade->type == FZ_MESH_TYPE7)
- return fz_bound_mesh_type4567(ctx, shade);
- else
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unexpected mesh type %d\n", shade->type);
- }
- fz_shade *
- fz_keep_shade(fz_context *ctx, fz_shade *shade)
- {
- return fz_keep_storable(ctx, &shade->storable);
- }
- void
- fz_drop_shade_imp(fz_context *ctx, fz_storable *shade_)
- {
- fz_shade *shade = (fz_shade *)shade_;
- fz_drop_colorspace(ctx, shade->colorspace);
- if (shade->type == FZ_FUNCTION_BASED)
- fz_free(ctx, shade->u.f.fn_vals);
- fz_drop_compressed_buffer(ctx, shade->buffer);
- fz_free(ctx, shade->function);
- fz_free(ctx, shade);
- }
- void
- fz_drop_shade(fz_context *ctx, fz_shade *shade)
- {
- fz_drop_storable(ctx, &shade->storable);
- }
- fz_rect
- fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm)
- {
- ctm = fz_concat(shade->matrix, ctm);
- if (shade->type != FZ_LINEAR && shade->type != FZ_RADIAL)
- {
- fz_rect rect = fz_bound_mesh(ctx, shade);
- rect = fz_intersect_rect(rect, shade->bbox);
- return fz_transform_rect(rect, ctm);
- }
- return fz_transform_rect(shade->bbox, ctm);
- }
|