shade.c 30 KB

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