dev_list.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. #include "fitz-internal.h"
  2. typedef struct fz_display_node_s fz_display_node;
  3. #define STACK_SIZE 96
  4. typedef enum fz_display_command_e
  5. {
  6. FZ_CMD_FILL_PATH,
  7. FZ_CMD_STROKE_PATH,
  8. FZ_CMD_CLIP_PATH,
  9. FZ_CMD_CLIP_STROKE_PATH,
  10. FZ_CMD_FILL_TEXT,
  11. FZ_CMD_STROKE_TEXT,
  12. FZ_CMD_CLIP_TEXT,
  13. FZ_CMD_CLIP_STROKE_TEXT,
  14. FZ_CMD_IGNORE_TEXT,
  15. FZ_CMD_FILL_SHADE,
  16. FZ_CMD_FILL_IMAGE,
  17. FZ_CMD_FILL_IMAGE_MASK,
  18. FZ_CMD_CLIP_IMAGE_MASK,
  19. FZ_CMD_POP_CLIP,
  20. FZ_CMD_BEGIN_MASK,
  21. FZ_CMD_END_MASK,
  22. FZ_CMD_BEGIN_GROUP,
  23. FZ_CMD_END_GROUP,
  24. FZ_CMD_BEGIN_TILE,
  25. FZ_CMD_END_TILE
  26. } fz_display_command;
  27. struct fz_display_node_s
  28. {
  29. fz_display_command cmd;
  30. fz_display_node *next;
  31. fz_rect rect;
  32. union {
  33. fz_path *path;
  34. fz_text *text;
  35. fz_shade *shade;
  36. fz_image *image;
  37. int blendmode;
  38. } item;
  39. fz_stroke_state *stroke;
  40. int flag; /* even_odd, accumulate, isolated/knockout... */
  41. fz_matrix ctm;
  42. fz_colorspace *colorspace;
  43. float alpha;
  44. float color[FZ_MAX_COLORS];
  45. };
  46. struct fz_display_list_s
  47. {
  48. fz_display_node *first;
  49. fz_display_node *last;
  50. int len;
  51. int top;
  52. struct {
  53. fz_rect *update;
  54. fz_rect rect;
  55. } stack[STACK_SIZE];
  56. int tiled;
  57. };
  58. enum { ISOLATED = 1, KNOCKOUT = 2 };
  59. static fz_display_node *
  60. fz_new_display_node(fz_context *ctx, fz_display_command cmd, const fz_matrix *ctm,
  61. fz_colorspace *colorspace, float *color, float alpha)
  62. {
  63. fz_display_node *node;
  64. int i;
  65. node = fz_malloc_struct(ctx, fz_display_node);
  66. node->cmd = cmd;
  67. node->next = NULL;
  68. node->rect = fz_empty_rect;
  69. node->item.path = NULL;
  70. node->stroke = NULL;
  71. node->flag = 0;
  72. node->ctm = *ctm;
  73. if (colorspace)
  74. {
  75. node->colorspace = fz_keep_colorspace(ctx, colorspace);
  76. if (color)
  77. {
  78. for (i = 0; i < node->colorspace->n; i++)
  79. node->color[i] = color[i];
  80. }
  81. }
  82. else
  83. {
  84. node->colorspace = NULL;
  85. }
  86. node->alpha = alpha;
  87. return node;
  88. }
  89. static void
  90. fz_append_display_node(fz_display_list *list, fz_display_node *node)
  91. {
  92. switch (node->cmd)
  93. {
  94. case FZ_CMD_CLIP_PATH:
  95. case FZ_CMD_CLIP_STROKE_PATH:
  96. case FZ_CMD_CLIP_IMAGE_MASK:
  97. if (list->top < STACK_SIZE)
  98. {
  99. list->stack[list->top].update = &node->rect;
  100. list->stack[list->top].rect = fz_empty_rect;
  101. }
  102. list->top++;
  103. break;
  104. case FZ_CMD_END_MASK:
  105. case FZ_CMD_CLIP_TEXT:
  106. case FZ_CMD_CLIP_STROKE_TEXT:
  107. if (list->top < STACK_SIZE)
  108. {
  109. list->stack[list->top].update = NULL;
  110. list->stack[list->top].rect = fz_empty_rect;
  111. }
  112. list->top++;
  113. break;
  114. case FZ_CMD_BEGIN_TILE:
  115. list->tiled++;
  116. if (list->top > 0 && list->top <= STACK_SIZE)
  117. {
  118. list->stack[list->top-1].rect = fz_infinite_rect;
  119. }
  120. break;
  121. case FZ_CMD_END_TILE:
  122. list->tiled--;
  123. break;
  124. case FZ_CMD_END_GROUP:
  125. break;
  126. case FZ_CMD_POP_CLIP:
  127. if (list->top > STACK_SIZE)
  128. {
  129. list->top--;
  130. node->rect = fz_infinite_rect;
  131. }
  132. else if (list->top > 0)
  133. {
  134. fz_rect *update;
  135. list->top--;
  136. update = list->stack[list->top].update;
  137. if (list->tiled == 0)
  138. {
  139. if (update)
  140. {
  141. fz_intersect_rect(update, &list->stack[list->top].rect);
  142. node->rect = *update;
  143. }
  144. else
  145. node->rect = list->stack[list->top].rect;
  146. }
  147. else
  148. node->rect = fz_infinite_rect;
  149. }
  150. /* fallthrough */
  151. default:
  152. if (list->top > 0 && list->tiled == 0 && list->top <= STACK_SIZE)
  153. fz_union_rect(&list->stack[list->top-1].rect, &node->rect);
  154. break;
  155. }
  156. if (!list->first)
  157. {
  158. list->first = node;
  159. list->last = node;
  160. }
  161. else
  162. {
  163. list->last->next = node;
  164. list->last = node;
  165. }
  166. list->len++;
  167. }
  168. static void
  169. fz_free_display_node(fz_context *ctx, fz_display_node *node)
  170. {
  171. switch (node->cmd)
  172. {
  173. case FZ_CMD_FILL_PATH:
  174. case FZ_CMD_STROKE_PATH:
  175. case FZ_CMD_CLIP_PATH:
  176. case FZ_CMD_CLIP_STROKE_PATH:
  177. fz_free_path(ctx, node->item.path);
  178. break;
  179. case FZ_CMD_FILL_TEXT:
  180. case FZ_CMD_STROKE_TEXT:
  181. case FZ_CMD_CLIP_TEXT:
  182. case FZ_CMD_CLIP_STROKE_TEXT:
  183. case FZ_CMD_IGNORE_TEXT:
  184. fz_free_text(ctx, node->item.text);
  185. break;
  186. case FZ_CMD_FILL_SHADE:
  187. fz_drop_shade(ctx, node->item.shade);
  188. break;
  189. case FZ_CMD_FILL_IMAGE:
  190. case FZ_CMD_FILL_IMAGE_MASK:
  191. case FZ_CMD_CLIP_IMAGE_MASK:
  192. fz_drop_image(ctx, node->item.image);
  193. break;
  194. case FZ_CMD_POP_CLIP:
  195. case FZ_CMD_BEGIN_MASK:
  196. case FZ_CMD_END_MASK:
  197. case FZ_CMD_BEGIN_GROUP:
  198. case FZ_CMD_END_GROUP:
  199. case FZ_CMD_BEGIN_TILE:
  200. case FZ_CMD_END_TILE:
  201. break;
  202. }
  203. if (node->stroke)
  204. fz_drop_stroke_state(ctx, node->stroke);
  205. if (node->colorspace)
  206. fz_drop_colorspace(ctx, node->colorspace);
  207. fz_free(ctx, node);
  208. }
  209. static void
  210. fz_list_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm,
  211. fz_colorspace *colorspace, float *color, float alpha)
  212. {
  213. fz_display_node *node;
  214. fz_context *ctx = dev->ctx;
  215. node = fz_new_display_node(ctx, FZ_CMD_FILL_PATH, ctm, colorspace, color, alpha);
  216. fz_try(ctx)
  217. {
  218. fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect);
  219. node->item.path = fz_clone_path(dev->ctx, path);
  220. node->flag = even_odd;
  221. }
  222. fz_catch(ctx)
  223. {
  224. fz_free_display_node(ctx, node);
  225. fz_rethrow(ctx);
  226. }
  227. fz_append_display_node(dev->user, node);
  228. }
  229. static void
  230. fz_list_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke,
  231. const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha)
  232. {
  233. fz_display_node *node;
  234. fz_context *ctx = dev->ctx;
  235. node = fz_new_display_node(ctx, FZ_CMD_STROKE_PATH, ctm, colorspace, color, alpha);
  236. fz_try(ctx)
  237. {
  238. fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect);
  239. node->item.path = fz_clone_path(dev->ctx, path);
  240. node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
  241. }
  242. fz_catch(ctx)
  243. {
  244. fz_free_display_node(ctx, node);
  245. fz_rethrow(ctx);
  246. }
  247. fz_append_display_node(dev->user, node);
  248. }
  249. static void
  250. fz_list_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm)
  251. {
  252. fz_display_node *node;
  253. fz_context *ctx = dev->ctx;
  254. node = fz_new_display_node(ctx, FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0);
  255. fz_try(ctx)
  256. {
  257. fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect);
  258. if (rect)
  259. fz_intersect_rect(&node->rect, rect);
  260. node->item.path = fz_clone_path(dev->ctx, path);
  261. node->flag = even_odd;
  262. }
  263. fz_catch(ctx)
  264. {
  265. fz_free_display_node(ctx, node);
  266. fz_rethrow(ctx);
  267. }
  268. fz_append_display_node(dev->user, node);
  269. }
  270. static void
  271. fz_list_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm)
  272. {
  273. fz_display_node *node;
  274. fz_context *ctx = dev->ctx;
  275. node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0);
  276. fz_try(ctx)
  277. {
  278. fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect);
  279. if (rect)
  280. fz_intersect_rect(&node->rect, rect);
  281. node->item.path = fz_clone_path(dev->ctx, path);
  282. node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
  283. }
  284. fz_catch(ctx)
  285. {
  286. fz_free_display_node(ctx, node);
  287. fz_rethrow(ctx);
  288. }
  289. fz_append_display_node(dev->user, node);
  290. }
  291. static void
  292. fz_list_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm,
  293. fz_colorspace *colorspace, float *color, float alpha)
  294. {
  295. fz_display_node *node;
  296. fz_context *ctx = dev->ctx;
  297. node = fz_new_display_node(ctx, FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha);
  298. fz_try(ctx)
  299. {
  300. fz_bound_text(dev->ctx, text, ctm, &node->rect);
  301. node->item.text = fz_clone_text(dev->ctx, text);
  302. }
  303. fz_catch(ctx)
  304. {
  305. fz_free_display_node(ctx, node);
  306. fz_rethrow(ctx);
  307. }
  308. fz_append_display_node(dev->user, node);
  309. }
  310. static void
  311. fz_list_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm,
  312. fz_colorspace *colorspace, float *color, float alpha)
  313. {
  314. fz_display_node *node;
  315. fz_context *ctx = dev->ctx;
  316. node = fz_new_display_node(ctx, FZ_CMD_STROKE_TEXT, ctm, colorspace, color, alpha);
  317. node->item.text = NULL;
  318. fz_try(ctx)
  319. {
  320. fz_bound_text(dev->ctx, text, ctm, &node->rect);
  321. fz_adjust_rect_for_stroke(&node->rect, stroke, ctm);
  322. node->item.text = fz_clone_text(dev->ctx, text);
  323. node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
  324. }
  325. fz_catch(ctx)
  326. {
  327. fz_free_display_node(ctx, node);
  328. fz_rethrow(ctx);
  329. }
  330. fz_append_display_node(dev->user, node);
  331. }
  332. static void
  333. fz_list_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate)
  334. {
  335. fz_display_node *node;
  336. fz_context *ctx = dev->ctx;
  337. node = fz_new_display_node(ctx, FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0);
  338. fz_try(ctx)
  339. {
  340. fz_bound_text(dev->ctx, text, ctm, &node->rect);
  341. node->item.text = fz_clone_text(dev->ctx, text);
  342. node->flag = accumulate;
  343. /* when accumulating, be conservative about culling */
  344. if (accumulate)
  345. node->rect = fz_infinite_rect;
  346. }
  347. fz_catch(ctx)
  348. {
  349. fz_free_display_node(ctx, node);
  350. fz_rethrow(ctx);
  351. }
  352. fz_append_display_node(dev->user, node);
  353. }
  354. static void
  355. fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm)
  356. {
  357. fz_display_node *node;
  358. fz_context *ctx = dev->ctx;
  359. node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0);
  360. fz_try(ctx)
  361. {
  362. fz_bound_text(dev->ctx, text, ctm, &node->rect);
  363. fz_adjust_rect_for_stroke(&node->rect, stroke, ctm);
  364. node->item.text = fz_clone_text(dev->ctx, text);
  365. node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
  366. }
  367. fz_catch(ctx)
  368. {
  369. fz_free_display_node(ctx, node);
  370. fz_rethrow(ctx);
  371. }
  372. fz_append_display_node(dev->user, node);
  373. }
  374. static void
  375. fz_list_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm)
  376. {
  377. fz_display_node *node;
  378. fz_context *ctx = dev->ctx;
  379. node = fz_new_display_node(ctx, FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0);
  380. fz_try(ctx)
  381. {
  382. fz_bound_text(dev->ctx, text, ctm, &node->rect);
  383. node->item.text = fz_clone_text(dev->ctx, text);
  384. }
  385. fz_catch(ctx)
  386. {
  387. fz_free_display_node(ctx, node);
  388. fz_rethrow(ctx);
  389. }
  390. fz_append_display_node(dev->user, node);
  391. }
  392. static void
  393. fz_list_pop_clip(fz_device *dev)
  394. {
  395. fz_display_node *node;
  396. node = fz_new_display_node(dev->ctx, FZ_CMD_POP_CLIP, &fz_identity, NULL, NULL, 0);
  397. fz_append_display_node(dev->user, node);
  398. }
  399. static void
  400. fz_list_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
  401. {
  402. fz_display_node *node;
  403. fz_context *ctx = dev->ctx;
  404. node = fz_new_display_node(ctx, FZ_CMD_FILL_SHADE, ctm, NULL, NULL, alpha);
  405. fz_bound_shade(ctx, shade, ctm, &node->rect);
  406. node->item.shade = fz_keep_shade(ctx, shade);
  407. fz_append_display_node(dev->user, node);
  408. }
  409. static void
  410. fz_list_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
  411. {
  412. fz_display_node *node;
  413. node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha);
  414. node->rect = fz_unit_rect;
  415. fz_transform_rect(&node->rect, ctm);
  416. node->item.image = fz_keep_image(dev->ctx, image);
  417. fz_append_display_node(dev->user, node);
  418. }
  419. static void
  420. fz_list_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm,
  421. fz_colorspace *colorspace, float *color, float alpha)
  422. {
  423. fz_display_node *node;
  424. node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha);
  425. node->rect = fz_unit_rect;
  426. fz_transform_rect(&node->rect, ctm);
  427. node->item.image = fz_keep_image(dev->ctx, image);
  428. fz_append_display_node(dev->user, node);
  429. }
  430. static void
  431. fz_list_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm)
  432. {
  433. fz_display_node *node;
  434. node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
  435. node->rect = fz_unit_rect;
  436. fz_transform_rect(&node->rect, ctm);
  437. if (rect)
  438. fz_intersect_rect(&node->rect, rect);
  439. node->item.image = fz_keep_image(dev->ctx, image);
  440. fz_append_display_node(dev->user, node);
  441. }
  442. static void
  443. fz_list_begin_mask(fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, float *color)
  444. {
  445. fz_display_node *node;
  446. node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_MASK, &fz_identity, colorspace, color, 0);
  447. node->rect = *rect;
  448. node->flag = luminosity;
  449. fz_append_display_node(dev->user, node);
  450. }
  451. static void
  452. fz_list_end_mask(fz_device *dev)
  453. {
  454. fz_display_node *node;
  455. node = fz_new_display_node(dev->ctx, FZ_CMD_END_MASK, &fz_identity, NULL, NULL, 0);
  456. fz_append_display_node(dev->user, node);
  457. }
  458. static void
  459. fz_list_begin_group(fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
  460. {
  461. fz_display_node *node;
  462. node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_GROUP, &fz_identity, NULL, NULL, alpha);
  463. node->rect = *rect;
  464. node->item.blendmode = blendmode;
  465. node->flag |= isolated ? ISOLATED : 0;
  466. node->flag |= knockout ? KNOCKOUT : 0;
  467. fz_append_display_node(dev->user, node);
  468. }
  469. static void
  470. fz_list_end_group(fz_device *dev)
  471. {
  472. fz_display_node *node;
  473. node = fz_new_display_node(dev->ctx, FZ_CMD_END_GROUP, &fz_identity, NULL, NULL, 0);
  474. fz_append_display_node(dev->user, node);
  475. }
  476. static void
  477. fz_list_begin_tile(fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm)
  478. {
  479. fz_display_node *node;
  480. node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_TILE, ctm, NULL, NULL, 0);
  481. node->rect = *area;
  482. node->color[0] = xstep;
  483. node->color[1] = ystep;
  484. node->color[2] = view->x0;
  485. node->color[3] = view->y0;
  486. node->color[4] = view->x1;
  487. node->color[5] = view->y1;
  488. fz_append_display_node(dev->user, node);
  489. }
  490. static void
  491. fz_list_end_tile(fz_device *dev)
  492. {
  493. fz_display_node *node;
  494. node = fz_new_display_node(dev->ctx, FZ_CMD_END_TILE, &fz_identity, NULL, NULL, 0);
  495. fz_append_display_node(dev->user, node);
  496. }
  497. fz_device *
  498. fz_new_list_device(fz_context *ctx, fz_display_list *list)
  499. {
  500. fz_device *dev = fz_new_device(ctx, list);
  501. dev->fill_path = fz_list_fill_path;
  502. dev->stroke_path = fz_list_stroke_path;
  503. dev->clip_path = fz_list_clip_path;
  504. dev->clip_stroke_path = fz_list_clip_stroke_path;
  505. dev->fill_text = fz_list_fill_text;
  506. dev->stroke_text = fz_list_stroke_text;
  507. dev->clip_text = fz_list_clip_text;
  508. dev->clip_stroke_text = fz_list_clip_stroke_text;
  509. dev->ignore_text = fz_list_ignore_text;
  510. dev->fill_shade = fz_list_fill_shade;
  511. dev->fill_image = fz_list_fill_image;
  512. dev->fill_image_mask = fz_list_fill_image_mask;
  513. dev->clip_image_mask = fz_list_clip_image_mask;
  514. dev->pop_clip = fz_list_pop_clip;
  515. dev->begin_mask = fz_list_begin_mask;
  516. dev->end_mask = fz_list_end_mask;
  517. dev->begin_group = fz_list_begin_group;
  518. dev->end_group = fz_list_end_group;
  519. dev->begin_tile = fz_list_begin_tile;
  520. dev->end_tile = fz_list_end_tile;
  521. return dev;
  522. }
  523. fz_display_list *
  524. fz_new_display_list(fz_context *ctx)
  525. {
  526. fz_display_list *list = fz_malloc_struct(ctx, fz_display_list);
  527. list->first = NULL;
  528. list->last = NULL;
  529. list->len = 0;
  530. list->top = 0;
  531. list->tiled = 0;
  532. return list;
  533. }
  534. void
  535. fz_free_display_list(fz_context *ctx, fz_display_list *list)
  536. {
  537. fz_display_node *node;
  538. if (list == NULL)
  539. return;
  540. node = list->first;
  541. while (node)
  542. {
  543. fz_display_node *next = node->next;
  544. fz_free_display_node(ctx, node);
  545. node = next;
  546. }
  547. fz_free(ctx, list);
  548. }
  549. void
  550. fz_run_display_list(fz_display_list *list, fz_device *dev, const fz_matrix *top_ctm, const fz_rect *scissor, fz_cookie *cookie)
  551. {
  552. fz_display_node *node;
  553. fz_matrix ctm;
  554. int clipped = 0;
  555. int tiled = 0;
  556. int empty;
  557. int progress = 0;
  558. fz_context *ctx = dev->ctx;
  559. if (!scissor)
  560. scissor = &fz_infinite_rect;
  561. if (cookie)
  562. {
  563. cookie->progress_max = list->len;
  564. cookie->progress = 0;
  565. }
  566. for (node = list->first; node; node = node->next)
  567. {
  568. /* Check the cookie for aborting */
  569. if (cookie)
  570. {
  571. if (cookie->abort)
  572. break;
  573. cookie->progress = progress++;
  574. }
  575. /* cull objects to draw using a quick visibility test */
  576. if (tiled || node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE)
  577. {
  578. empty = 0;
  579. }
  580. else
  581. {
  582. fz_rect rect = node->rect;
  583. fz_intersect_rect(fz_transform_rect(&rect, top_ctm), scissor);
  584. empty = fz_is_empty_rect(&rect);
  585. }
  586. if (clipped || empty)
  587. {
  588. switch (node->cmd)
  589. {
  590. case FZ_CMD_CLIP_PATH:
  591. case FZ_CMD_CLIP_STROKE_PATH:
  592. case FZ_CMD_CLIP_STROKE_TEXT:
  593. case FZ_CMD_CLIP_IMAGE_MASK:
  594. case FZ_CMD_BEGIN_MASK:
  595. case FZ_CMD_BEGIN_GROUP:
  596. clipped++;
  597. continue;
  598. case FZ_CMD_CLIP_TEXT:
  599. /* Accumulated text has no extra pops */
  600. if (node->flag != 2)
  601. clipped++;
  602. continue;
  603. case FZ_CMD_POP_CLIP:
  604. case FZ_CMD_END_GROUP:
  605. if (!clipped)
  606. goto visible;
  607. clipped--;
  608. continue;
  609. case FZ_CMD_END_MASK:
  610. if (!clipped)
  611. goto visible;
  612. continue;
  613. default:
  614. continue;
  615. }
  616. }
  617. visible:
  618. fz_concat(&ctm, &node->ctm, top_ctm);
  619. fz_try(ctx)
  620. {
  621. switch (node->cmd)
  622. {
  623. case FZ_CMD_FILL_PATH:
  624. fz_fill_path(dev, node->item.path, node->flag, &ctm,
  625. node->colorspace, node->color, node->alpha);
  626. break;
  627. case FZ_CMD_STROKE_PATH:
  628. fz_stroke_path(dev, node->item.path, node->stroke, &ctm,
  629. node->colorspace, node->color, node->alpha);
  630. break;
  631. case FZ_CMD_CLIP_PATH:
  632. {
  633. fz_rect rect = node->rect;
  634. fz_transform_rect(&rect, top_ctm);
  635. fz_clip_path(dev, node->item.path, &rect, node->flag, &ctm);
  636. break;
  637. }
  638. case FZ_CMD_CLIP_STROKE_PATH:
  639. {
  640. fz_rect rect = node->rect;
  641. fz_transform_rect(&rect, top_ctm);
  642. fz_clip_stroke_path(dev, node->item.path, &rect, node->stroke, &ctm);
  643. break;
  644. }
  645. case FZ_CMD_FILL_TEXT:
  646. fz_fill_text(dev, node->item.text, &ctm,
  647. node->colorspace, node->color, node->alpha);
  648. break;
  649. case FZ_CMD_STROKE_TEXT:
  650. fz_stroke_text(dev, node->item.text, node->stroke, &ctm,
  651. node->colorspace, node->color, node->alpha);
  652. break;
  653. case FZ_CMD_CLIP_TEXT:
  654. fz_clip_text(dev, node->item.text, &ctm, node->flag);
  655. break;
  656. case FZ_CMD_CLIP_STROKE_TEXT:
  657. fz_clip_stroke_text(dev, node->item.text, node->stroke, &ctm);
  658. break;
  659. case FZ_CMD_IGNORE_TEXT:
  660. fz_ignore_text(dev, node->item.text, &ctm);
  661. break;
  662. case FZ_CMD_FILL_SHADE:
  663. fz_fill_shade(dev, node->item.shade, &ctm, node->alpha);
  664. break;
  665. case FZ_CMD_FILL_IMAGE:
  666. fz_fill_image(dev, node->item.image, &ctm, node->alpha);
  667. break;
  668. case FZ_CMD_FILL_IMAGE_MASK:
  669. fz_fill_image_mask(dev, node->item.image, &ctm,
  670. node->colorspace, node->color, node->alpha);
  671. break;
  672. case FZ_CMD_CLIP_IMAGE_MASK:
  673. {
  674. fz_rect rect = node->rect;
  675. fz_transform_rect(&rect, top_ctm);
  676. fz_clip_image_mask(dev, node->item.image, &rect, &ctm);
  677. break;
  678. }
  679. case FZ_CMD_POP_CLIP:
  680. fz_pop_clip(dev);
  681. break;
  682. case FZ_CMD_BEGIN_MASK:
  683. {
  684. fz_rect rect = node->rect;
  685. fz_transform_rect(&rect, top_ctm);
  686. fz_begin_mask(dev, &rect, node->flag, node->colorspace, node->color);
  687. break;
  688. }
  689. case FZ_CMD_END_MASK:
  690. fz_end_mask(dev);
  691. break;
  692. case FZ_CMD_BEGIN_GROUP:
  693. {
  694. fz_rect rect = node->rect;
  695. fz_transform_rect(&rect, top_ctm);
  696. fz_begin_group(dev, &rect,
  697. (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
  698. node->item.blendmode, node->alpha);
  699. break;
  700. }
  701. case FZ_CMD_END_GROUP:
  702. fz_end_group(dev);
  703. break;
  704. case FZ_CMD_BEGIN_TILE:
  705. {
  706. fz_rect rect;
  707. tiled++;
  708. rect.x0 = node->color[2];
  709. rect.y0 = node->color[3];
  710. rect.x1 = node->color[4];
  711. rect.y1 = node->color[5];
  712. fz_begin_tile(dev, &node->rect, &rect, node->color[0], node->color[1], &ctm);
  713. break;
  714. }
  715. case FZ_CMD_END_TILE:
  716. tiled--;
  717. fz_end_tile(dev);
  718. break;
  719. }
  720. }
  721. fz_catch(ctx)
  722. {
  723. /* Swallow the error */
  724. if (cookie)
  725. cookie->errors++;
  726. fz_warn(ctx, "Ignoring error during interpretation");
  727. }
  728. }
  729. }