pdf-op-filter.c 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037
  1. // Copyright (C) 2004-2025 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 "mupdf/pdf.h"
  24. #include "pdf-imp.h"
  25. #include <string.h>
  26. typedef enum
  27. {
  28. FLUSH_CTM = 1,
  29. FLUSH_COLOR_F = 2,
  30. FLUSH_COLOR_S = 4,
  31. FLUSH_TEXT = 8,
  32. FLUSH_OP = 16,
  33. FLUSH_ALL = 15,
  34. FLUSH_STROKE = 1+4,
  35. FLUSH_FILL = 1+2
  36. } gstate_flush_flags;
  37. typedef struct pdf_filter_gstate_sc
  38. {
  39. char name[256];
  40. pdf_pattern *pat;
  41. fz_shade *shd;
  42. int n;
  43. float c[FZ_MAX_COLORS];
  44. } pdf_filter_gstate_sc;
  45. typedef struct pdf_filter_gstate
  46. {
  47. fz_matrix ctm;
  48. struct
  49. {
  50. char name[256];
  51. fz_colorspace *cs;
  52. } cs, CS;
  53. pdf_filter_gstate_sc sc, SC;
  54. struct
  55. {
  56. fz_linecap linecap;
  57. fz_linejoin linejoin;
  58. float linewidth;
  59. float miterlimit;
  60. } stroke;
  61. pdf_text_state text;
  62. } pdf_filter_gstate;
  63. typedef enum
  64. {
  65. NO_CLIP_OP,
  66. CLIP_W,
  67. CLIP_Wstar
  68. } clip_op_t;
  69. typedef struct filter_gstate
  70. {
  71. struct filter_gstate *next;
  72. int pushed;
  73. fz_rect clip_rect;
  74. pdf_filter_gstate pending;
  75. pdf_filter_gstate sent;
  76. clip_op_t clip_op;
  77. } filter_gstate;
  78. typedef struct
  79. {
  80. char *utf8;
  81. int edited;
  82. int pos;
  83. } editable_str;
  84. typedef struct tag_record
  85. {
  86. int bdc;
  87. char *tag;
  88. pdf_obj *raw;
  89. pdf_obj *cooked;
  90. int mcid_num;
  91. pdf_obj *mcid_obj;
  92. editable_str alt;
  93. editable_str actualtext;
  94. struct tag_record *prev;
  95. } tag_record;
  96. typedef struct resources_stack
  97. {
  98. struct resources_stack *next;
  99. pdf_obj *old_rdb;
  100. pdf_obj *new_rdb;
  101. } resources_stack;
  102. typedef struct
  103. {
  104. pdf_processor super;
  105. pdf_document *doc;
  106. int structparents;
  107. pdf_obj *structarray;
  108. pdf_processor *chain;
  109. filter_gstate *gstate;
  110. pdf_text_object_state tos;
  111. /* If Td_pending, then any Tm_pending can be ignored and we can just
  112. * send a Td with Td_value rather than the Tm. */
  113. int Td_pending;
  114. fz_point Td_value;
  115. int Tm_pending;
  116. int BT_pending;
  117. int in_BT;
  118. float Tm_adjust;
  119. tag_record *current_tags;
  120. tag_record *pending_tags;
  121. resources_stack *rstack;
  122. pdf_sanitize_filter_options *options;
  123. fz_matrix transform;
  124. /* Has any marking text been sent so far this text object? */
  125. int text_sent;
  126. /* Has any marking text been removed so far this text object? */
  127. int text_removed;
  128. pdf_filter_options *global_options;
  129. fz_path *path;
  130. } pdf_sanitize_processor;
  131. static void
  132. copy_resource(fz_context *ctx, pdf_sanitize_processor *p, pdf_obj *key, const char *name)
  133. {
  134. pdf_obj *res, *obj;
  135. if (!name || name[0] == 0)
  136. return;
  137. res = pdf_dict_get(ctx, p->rstack->old_rdb, key);
  138. obj = pdf_dict_gets(ctx, res, name);
  139. if (obj)
  140. {
  141. res = pdf_dict_get(ctx, p->rstack->new_rdb, key);
  142. if (!res)
  143. {
  144. res = pdf_new_dict(ctx, pdf_get_bound_document(ctx, p->rstack->new_rdb), 1);
  145. pdf_dict_put_drop(ctx, p->rstack->new_rdb, key, res);
  146. }
  147. pdf_dict_putp(ctx, res, name, obj);
  148. }
  149. }
  150. static void
  151. add_resource(fz_context *ctx, pdf_sanitize_processor *p, pdf_obj *key, const char *name, pdf_obj *val)
  152. {
  153. pdf_obj *res = pdf_dict_get(ctx, p->rstack->new_rdb, key);
  154. if (!res)
  155. res = pdf_dict_put_dict(ctx, p->rstack->new_rdb, key, 8);
  156. pdf_dict_puts(ctx, res, name, val);
  157. }
  158. static void
  159. create_resource_name(fz_context *ctx, pdf_sanitize_processor *p, pdf_obj *key, const char *prefix, char *buf, int len)
  160. {
  161. int i;
  162. pdf_obj *res = pdf_dict_get(ctx, p->rstack->new_rdb, key);
  163. if (!res)
  164. res = pdf_dict_put_dict(ctx, p->rstack->new_rdb, key, 8);
  165. for (i = 1; i < 65536; ++i)
  166. {
  167. fz_snprintf(buf, len, "%s%d", prefix, i);
  168. if (!pdf_dict_gets(ctx, res, buf))
  169. return;
  170. }
  171. fz_throw(ctx, FZ_ERROR_LIMIT, "Cannot create unique resource name");
  172. }
  173. static void
  174. filter_push(fz_context *ctx, pdf_sanitize_processor *p)
  175. {
  176. filter_gstate *gstate = p->gstate;
  177. filter_gstate *new_gstate = fz_malloc_struct(ctx, filter_gstate);
  178. *new_gstate = *gstate;
  179. new_gstate->pushed = 0;
  180. new_gstate->next = gstate;
  181. p->gstate = new_gstate;
  182. pdf_keep_font(ctx, new_gstate->pending.text.font);
  183. fz_keep_string(ctx, new_gstate->pending.text.fontname);
  184. pdf_keep_font(ctx, new_gstate->sent.text.font);
  185. fz_keep_string(ctx, new_gstate->sent.text.fontname);
  186. }
  187. static int
  188. filter_pop(fz_context *ctx, pdf_sanitize_processor *p)
  189. {
  190. filter_gstate *gstate = p->gstate;
  191. filter_gstate *old = gstate->next;
  192. /* We are at the top, so nothing to pop! */
  193. if (old == NULL)
  194. return 1;
  195. if (gstate->pushed)
  196. if (p->chain->op_Q)
  197. p->chain->op_Q(ctx, p->chain);
  198. pdf_drop_font(ctx, gstate->pending.text.font);
  199. fz_drop_string(ctx, gstate->pending.text.fontname);
  200. pdf_drop_font(ctx, gstate->sent.text.font);
  201. fz_drop_string(ctx, gstate->sent.text.fontname);
  202. fz_free(ctx, gstate);
  203. p->gstate = old;
  204. return 0;
  205. }
  206. static void flush_tags(fz_context *ctx, pdf_sanitize_processor *p, tag_record **tags)
  207. {
  208. tag_record *tag = *tags;
  209. if (tag == NULL)
  210. return;
  211. if (tag->prev)
  212. flush_tags(ctx, p, &tag->prev);
  213. if (tag->bdc)
  214. {
  215. if (p->chain->op_BDC)
  216. p->chain->op_BDC(ctx, p->chain, tag->tag, tag->raw, tag->cooked);
  217. }
  218. else if (p->chain->op_BMC)
  219. p->chain->op_BMC(ctx, p->chain, tag->tag);
  220. tag->prev = p->current_tags;
  221. p->current_tags = tag;
  222. *tags = NULL;
  223. }
  224. static filter_gstate *
  225. ensure_pushed(fz_context *ctx, pdf_sanitize_processor *p)
  226. {
  227. filter_gstate *gstate = p->gstate;
  228. if (gstate->next)
  229. {
  230. /* We are not the top gstate. */
  231. if (p->gstate->pushed == 0)
  232. {
  233. p->gstate->pushed = 1;
  234. if (p->chain->op_q)
  235. p->chain->op_q(ctx, p->chain);
  236. }
  237. return gstate;
  238. }
  239. /* So gstate is the top one. We want at least one pushed. */
  240. filter_push(ctx, p);
  241. p->gstate->pushed = 1;
  242. if (p->chain->op_q)
  243. p->chain->op_q(ctx, p->chain);
  244. /* Now, gstate->pending has all been copied onto new_gstate->pending.
  245. * So put, gstate->pending back to sanity. */
  246. pdf_drop_font(ctx, gstate->pending.text.font);
  247. fz_drop_string(ctx, gstate->pending.text.fontname);
  248. gstate->pending = p->gstate->next->sent;
  249. pdf_keep_font(ctx, gstate->pending.text.font);
  250. fz_keep_string(ctx, gstate->pending.text.fontname);
  251. return p->gstate;
  252. }
  253. static void filter_flush(fz_context *ctx, pdf_sanitize_processor *p, int flush)
  254. {
  255. filter_gstate *gstate = p->gstate;
  256. int i;
  257. /* No point in sending anything if we're clipping it away! */
  258. if (fz_is_empty_rect(p->gstate->clip_rect))
  259. return;
  260. if (flush)
  261. flush_tags(ctx, p, &p->pending_tags);
  262. if (flush & FLUSH_OP)
  263. gstate = ensure_pushed(ctx, p);
  264. if (flush & FLUSH_CTM)
  265. {
  266. if (gstate->pending.ctm.a != 1 || gstate->pending.ctm.b != 0 ||
  267. gstate->pending.ctm.c != 0 || gstate->pending.ctm.d != 1 ||
  268. gstate->pending.ctm.e != 0 || gstate->pending.ctm.f != 0)
  269. {
  270. fz_matrix current = gstate->sent.ctm;
  271. gstate = ensure_pushed(ctx, p);
  272. if (p->chain->op_cm)
  273. p->chain->op_cm(ctx, p->chain,
  274. gstate->pending.ctm.a,
  275. gstate->pending.ctm.b,
  276. gstate->pending.ctm.c,
  277. gstate->pending.ctm.d,
  278. gstate->pending.ctm.e,
  279. gstate->pending.ctm.f);
  280. gstate->sent.ctm = fz_concat(gstate->pending.ctm, current);
  281. gstate->pending.ctm.a = 1;
  282. gstate->pending.ctm.b = 0;
  283. gstate->pending.ctm.c = 0;
  284. gstate->pending.ctm.d = 1;
  285. gstate->pending.ctm.e = 0;
  286. gstate->pending.ctm.f = 0;
  287. }
  288. }
  289. if (flush & FLUSH_COLOR_F)
  290. {
  291. if (gstate->pending.cs.cs == fz_device_gray(ctx) && !gstate->pending.sc.pat && !gstate->pending.sc.shd && gstate->pending.sc.n == 1 &&
  292. (gstate->sent.cs.cs != fz_device_gray(ctx) || gstate->sent.sc.pat || gstate->sent.sc.shd || gstate->sent.sc.n != 1 || gstate->pending.sc.c[0] != gstate->sent.sc.c[0]))
  293. {
  294. gstate = ensure_pushed(ctx, p);
  295. if (p->chain->op_g)
  296. p->chain->op_g(ctx, p->chain, gstate->pending.sc.c[0]);
  297. goto done_sc;
  298. }
  299. if (gstate->pending.cs.cs == fz_device_rgb(ctx) && !gstate->pending.sc.pat && !gstate->pending.sc.shd && gstate->pending.sc.n == 3 &&
  300. (gstate->sent.cs.cs != fz_device_rgb(ctx) || gstate->sent.sc.pat || gstate->sent.sc.shd || gstate->sent.sc.n != 3 || gstate->pending.sc.c[0] != gstate->sent.sc.c[0] ||
  301. gstate->pending.sc.c[1] != gstate->sent.sc.c[1] || gstate->pending.sc.c[1] != gstate->sent.sc.c[1]))
  302. {
  303. gstate = ensure_pushed(ctx, p);
  304. if (p->chain->op_rg)
  305. p->chain->op_rg(ctx, p->chain, gstate->pending.sc.c[0], gstate->pending.sc.c[1], gstate->pending.sc.c[2]);
  306. goto done_sc;
  307. }
  308. if (gstate->pending.cs.cs == fz_device_cmyk(ctx) && !gstate->pending.sc.pat && !gstate->pending.sc.shd && gstate->pending.sc.n == 4 &&
  309. (gstate->sent.cs.cs != fz_device_cmyk(ctx) || gstate->sent.sc.pat || gstate->sent.sc.shd || gstate->pending.sc.n != 4 || gstate->pending.sc.c[0] != gstate->sent.sc.c[0] ||
  310. gstate->pending.sc.c[1] != gstate->sent.sc.c[1] || gstate->pending.sc.c[2] != gstate->sent.sc.c[2] || gstate->pending.sc.c[3] != gstate->sent.sc.c[3]))
  311. {
  312. gstate = ensure_pushed(ctx, p);
  313. if (p->chain->op_k)
  314. p->chain->op_k(ctx, p->chain, gstate->pending.sc.c[0], gstate->pending.sc.c[1], gstate->pending.sc.c[2], gstate->pending.sc.c[3]);
  315. goto done_sc;
  316. }
  317. if (strcmp(gstate->pending.cs.name, gstate->sent.cs.name))
  318. {
  319. gstate = ensure_pushed(ctx, p);
  320. if (p->chain->op_cs)
  321. p->chain->op_cs(ctx, p->chain, gstate->pending.cs.name, gstate->pending.cs.cs);
  322. }
  323. /* pattern or shading */
  324. if (gstate->pending.sc.name[0])
  325. {
  326. int emit = 0;
  327. if (strcmp(gstate->pending.sc.name, gstate->sent.sc.name))
  328. emit = 1;
  329. if (gstate->pending.sc.n != gstate->sent.sc.n)
  330. emit = 1;
  331. else
  332. for (i = 0; i < gstate->pending.sc.n; ++i)
  333. if (gstate->pending.sc.c[i] != gstate->sent.sc.c[i])
  334. emit = 1;
  335. if (emit)
  336. {
  337. gstate = ensure_pushed(ctx, p);
  338. if (gstate->pending.sc.pat)
  339. if (p->chain->op_sc_pattern)
  340. p->chain->op_sc_pattern(ctx, p->chain, gstate->pending.sc.name, gstate->pending.sc.pat, gstate->pending.sc.n, gstate->pending.sc.c);
  341. if (gstate->pending.sc.shd)
  342. if (p->chain->op_sc_shade)
  343. p->chain->op_sc_shade(ctx, p->chain, gstate->pending.sc.name, gstate->pending.sc.shd);
  344. }
  345. }
  346. /* plain color */
  347. else
  348. {
  349. int emit = 0;
  350. if (gstate->pending.sc.n != gstate->sent.sc.n)
  351. emit = 1;
  352. else
  353. for (i = 0; i < gstate->pending.sc.n; ++i)
  354. if (gstate->pending.sc.c[i] != gstate->sent.sc.c[i])
  355. emit = 1;
  356. if (emit)
  357. {
  358. gstate = ensure_pushed(ctx, p);
  359. if (p->chain->op_sc_color)
  360. p->chain->op_sc_color(ctx, p->chain, gstate->pending.sc.n, gstate->pending.sc.c);
  361. }
  362. }
  363. done_sc:
  364. gstate->sent.cs = gstate->pending.cs;
  365. gstate->sent.sc = gstate->pending.sc;
  366. }
  367. if (flush & FLUSH_COLOR_S)
  368. {
  369. if (gstate->pending.CS.cs == fz_device_gray(ctx) && !gstate->pending.SC.pat && !gstate->pending.SC.shd && gstate->pending.SC.n == 1 &&
  370. (gstate->sent.CS.cs != fz_device_gray(ctx) || gstate->sent.SC.pat || gstate->sent.SC.shd || gstate->sent.SC.n != 0 || gstate->pending.SC.c[0] != gstate->sent.SC.c[0]))
  371. {
  372. gstate = ensure_pushed(ctx, p);
  373. if (p->chain->op_G)
  374. p->chain->op_G(ctx, p->chain, gstate->pending.SC.c[0]);
  375. goto done_SC;
  376. }
  377. if (gstate->pending.CS.cs == fz_device_rgb(ctx) && !gstate->pending.SC.pat && !gstate->pending.SC.shd && gstate->pending.SC.n == 3 &&
  378. (gstate->sent.CS.cs != fz_device_rgb(ctx) || gstate->sent.SC.pat || gstate->sent.SC.shd || gstate->sent.SC.n != 3 || gstate->pending.SC.c[0] != gstate->sent.SC.c[0] ||
  379. gstate->pending.SC.c[1] != gstate->sent.SC.c[1] || gstate->pending.SC.c[1] != gstate->sent.SC.c[1]))
  380. {
  381. gstate = ensure_pushed(ctx, p);
  382. if (p->chain->op_RG)
  383. p->chain->op_RG(ctx, p->chain, gstate->pending.SC.c[0], gstate->pending.SC.c[1], gstate->pending.SC.c[2]);
  384. goto done_SC;
  385. }
  386. if (gstate->pending.CS.cs == fz_device_cmyk(ctx) && !gstate->pending.SC.pat && !gstate->pending.SC.shd && gstate->pending.SC.n == 4 &&
  387. (gstate->sent.CS.cs != fz_device_cmyk(ctx) || gstate->sent.SC.pat || gstate->sent.SC.shd || gstate->pending.SC.n != 4 || gstate->pending.SC.c[0] != gstate->sent.SC.c[0] ||
  388. gstate->pending.SC.c[1] != gstate->sent.SC.c[1] || gstate->pending.SC.c[2] != gstate->sent.SC.c[2] || gstate->pending.SC.c[3] != gstate->sent.SC.c[3]))
  389. {
  390. gstate = ensure_pushed(ctx, p);
  391. if (p->chain->op_K)
  392. p->chain->op_K(ctx, p->chain, gstate->pending.SC.c[0], gstate->pending.SC.c[1], gstate->pending.SC.c[2], gstate->pending.SC.c[3]);
  393. goto done_SC;
  394. }
  395. if (strcmp(gstate->pending.CS.name, gstate->sent.CS.name))
  396. {
  397. gstate = ensure_pushed(ctx, p);
  398. if (p->chain->op_CS)
  399. p->chain->op_CS(ctx, p->chain, gstate->pending.CS.name, gstate->pending.CS.cs);
  400. }
  401. /* pattern or shading */
  402. if (gstate->pending.SC.name[0])
  403. {
  404. int emit = 0;
  405. if (strcmp(gstate->pending.SC.name, gstate->sent.SC.name))
  406. emit = 1;
  407. if (gstate->pending.SC.n != gstate->sent.SC.n)
  408. emit = 1;
  409. else
  410. for (i = 0; i < gstate->pending.SC.n; ++i)
  411. if (gstate->pending.SC.c[i] != gstate->sent.SC.c[i])
  412. emit = 1;
  413. if (emit)
  414. {
  415. gstate = ensure_pushed(ctx, p);
  416. if (gstate->pending.SC.pat)
  417. if (p->chain->op_SC_pattern)
  418. p->chain->op_SC_pattern(ctx, p->chain, gstate->pending.SC.name, gstate->pending.SC.pat, gstate->pending.SC.n, gstate->pending.SC.c);
  419. if (gstate->pending.SC.shd)
  420. if (p->chain->op_SC_shade)
  421. p->chain->op_SC_shade(ctx, p->chain, gstate->pending.SC.name, gstate->pending.SC.shd);
  422. }
  423. }
  424. /* plain color */
  425. else
  426. {
  427. int emit = 0;
  428. if (gstate->pending.SC.n != gstate->sent.SC.n)
  429. emit = 1;
  430. else
  431. for (i = 0; i < gstate->pending.SC.n; ++i)
  432. if (gstate->pending.SC.c[i] != gstate->sent.SC.c[i])
  433. emit = 1;
  434. if (emit)
  435. {
  436. gstate = ensure_pushed(ctx, p);
  437. if (p->chain->op_SC_color)
  438. p->chain->op_SC_color(ctx, p->chain, gstate->pending.SC.n, gstate->pending.SC.c);
  439. }
  440. }
  441. done_SC:
  442. gstate->sent.CS = gstate->pending.CS;
  443. gstate->sent.SC = gstate->pending.SC;
  444. }
  445. if (flush & FLUSH_STROKE)
  446. {
  447. if (gstate->pending.stroke.linecap != gstate->sent.stroke.linecap)
  448. {
  449. gstate = ensure_pushed(ctx, p);
  450. if (p->chain->op_J)
  451. p->chain->op_J(ctx, p->chain, gstate->pending.stroke.linecap);
  452. }
  453. if (gstate->pending.stroke.linejoin != gstate->sent.stroke.linejoin)
  454. {
  455. gstate = ensure_pushed(ctx, p);
  456. if (p->chain->op_j)
  457. p->chain->op_j(ctx, p->chain, gstate->pending.stroke.linejoin);
  458. }
  459. if (gstate->pending.stroke.linewidth != gstate->sent.stroke.linewidth)
  460. {
  461. gstate = ensure_pushed(ctx, p);
  462. if (p->chain->op_w)
  463. p->chain->op_w(ctx, p->chain, gstate->pending.stroke.linewidth);
  464. }
  465. if (gstate->pending.stroke.miterlimit != gstate->sent.stroke.miterlimit)
  466. {
  467. gstate = ensure_pushed(ctx, p);
  468. if (p->chain->op_M)
  469. p->chain->op_M(ctx, p->chain, gstate->pending.stroke.miterlimit);
  470. }
  471. gstate->sent.stroke = gstate->pending.stroke;
  472. }
  473. if (flush & FLUSH_TEXT)
  474. {
  475. if (p->BT_pending)
  476. {
  477. gstate = ensure_pushed(ctx, p);
  478. if (p->chain->op_BT)
  479. p->chain->op_BT(ctx, p->chain);
  480. p->BT_pending = 0;
  481. p->in_BT = 1;
  482. p->text_sent = 0;
  483. p->text_removed = 0;
  484. }
  485. if (p->in_BT)
  486. {
  487. if (gstate->pending.text.char_space != gstate->sent.text.char_space)
  488. {
  489. gstate = ensure_pushed(ctx, p);
  490. if (p->chain->op_Tc)
  491. p->chain->op_Tc(ctx, p->chain, gstate->pending.text.char_space);
  492. }
  493. if (gstate->pending.text.word_space != gstate->sent.text.word_space)
  494. {
  495. gstate = ensure_pushed(ctx, p);
  496. if (p->chain->op_Tw)
  497. p->chain->op_Tw(ctx, p->chain, gstate->pending.text.word_space);
  498. }
  499. if (gstate->pending.text.scale != gstate->sent.text.scale)
  500. {
  501. /* The value of scale in the gstate is divided by 100 from what is written in the file */
  502. gstate = ensure_pushed(ctx, p);
  503. if (p->chain->op_Tz)
  504. p->chain->op_Tz(ctx, p->chain, gstate->pending.text.scale*100);
  505. }
  506. if (gstate->pending.text.leading != gstate->sent.text.leading)
  507. {
  508. gstate = ensure_pushed(ctx, p);
  509. if (p->chain->op_TL)
  510. p->chain->op_TL(ctx, p->chain, gstate->pending.text.leading);
  511. }
  512. if (gstate->pending.text.font != gstate->sent.text.font ||
  513. gstate->pending.text.size != gstate->sent.text.size ||
  514. gstate->pending.text.fontname != gstate->sent.text.fontname)
  515. {
  516. gstate = ensure_pushed(ctx, p);
  517. if (p->chain->op_Tf)
  518. p->chain->op_Tf(ctx, p->chain, fz_cstring_from_string(gstate->pending.text.fontname), gstate->pending.text.font, gstate->pending.text.size);
  519. }
  520. if (gstate->pending.text.render != gstate->sent.text.render)
  521. {
  522. gstate = ensure_pushed(ctx, p);
  523. if (p->chain->op_Tr)
  524. p->chain->op_Tr(ctx, p->chain, gstate->pending.text.render);
  525. }
  526. if (gstate->pending.text.rise != gstate->sent.text.rise)
  527. {
  528. gstate = ensure_pushed(ctx, p);
  529. if (p->chain->op_Ts)
  530. p->chain->op_Ts(ctx, p->chain, gstate->pending.text.rise);
  531. }
  532. pdf_drop_font(ctx, gstate->sent.text.font);
  533. fz_drop_string(ctx, gstate->sent.text.fontname);
  534. gstate->sent.text = gstate->pending.text;
  535. gstate->sent.text.font = pdf_keep_font(ctx, gstate->pending.text.font);
  536. gstate->sent.text.fontname = fz_keep_string(ctx, gstate->pending.text.fontname);
  537. if (p->Td_pending != 0)
  538. {
  539. gstate = ensure_pushed(ctx, p);
  540. if (p->chain->op_Td)
  541. p->chain->op_Td(ctx, p->chain, p->Td_value.x, p->Td_value.y);
  542. p->Tm_pending = 0;
  543. p->Td_pending = 0;
  544. }
  545. else if (p->Tm_pending != 0)
  546. {
  547. gstate = ensure_pushed(ctx, p);
  548. if (p->chain->op_Tm)
  549. p->chain->op_Tm(ctx, p->chain, p->tos.tlm.a, p->tos.tlm.b, p->tos.tlm.c, p->tos.tlm.d, p->tos.tlm.e, p->tos.tlm.f);
  550. p->Tm_pending = 0;
  551. }
  552. }
  553. }
  554. }
  555. static int
  556. filter_show_char(fz_context *ctx, pdf_sanitize_processor *p, int cid, int *unicode)
  557. {
  558. filter_gstate *gstate = p->gstate;
  559. pdf_font_desc *fontdesc = gstate->pending.text.font;
  560. fz_matrix trm;
  561. int ucsbuf[PDF_MRANGE_CAP];
  562. int ucslen;
  563. int remove = 0;
  564. float adv;
  565. (void)pdf_tos_make_trm(ctx, &p->tos, &gstate->pending.text, fontdesc, cid, &trm, &adv);
  566. ucslen = 0;
  567. if (fontdesc->to_unicode)
  568. ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
  569. if (ucslen == 0 && (size_t)cid < fontdesc->cid_to_ucs_len)
  570. {
  571. ucsbuf[0] = fontdesc->cid_to_ucs[cid];
  572. ucslen = 1;
  573. }
  574. if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
  575. {
  576. ucsbuf[0] = FZ_REPLACEMENT_CHARACTER;
  577. ucslen = 1;
  578. }
  579. *unicode = ucsbuf[0];
  580. if (p->options->text_filter || p->options->culler)
  581. {
  582. fz_matrix ctm;
  583. fz_rect bbox;
  584. ctm = fz_concat(gstate->pending.ctm, gstate->sent.ctm);
  585. ctm = fz_concat(ctm, p->transform);
  586. if (fontdesc->wmode == 0)
  587. {
  588. bbox.x0 = 0;
  589. bbox.y0 = fz_font_descender(ctx, fontdesc->font);
  590. bbox.x1 = fz_advance_glyph(ctx, fontdesc->font, p->tos.gid, 0);
  591. bbox.y1 = fz_font_ascender(ctx, fontdesc->font);
  592. }
  593. else
  594. {
  595. fz_rect font_bbox = fz_font_bbox(ctx, fontdesc->font);
  596. bbox.x0 = font_bbox.x0;
  597. bbox.x1 = font_bbox.x1;
  598. bbox.y0 = 0;
  599. bbox.y1 = fz_advance_glyph(ctx, fontdesc->font, p->tos.gid, 1);
  600. }
  601. if (p->options->text_filter)
  602. remove = p->options->text_filter(ctx, p->options->opaque, ucsbuf, ucslen, trm, ctm, bbox);
  603. if (p->options->culler && !remove)
  604. {
  605. ctm = fz_concat(trm, ctm);
  606. bbox = fz_transform_rect(bbox, ctm);
  607. remove = p->options->culler(ctx, p->options->opaque, bbox, FZ_CULL_GLYPH);
  608. }
  609. }
  610. pdf_tos_move_after_char(ctx, &p->tos);
  611. return remove;
  612. }
  613. static void
  614. filter_show_space(fz_context *ctx, pdf_sanitize_processor *p, float tadj)
  615. {
  616. filter_gstate *gstate = p->gstate;
  617. pdf_font_desc *fontdesc = gstate->pending.text.font;
  618. if (fontdesc->wmode == 0)
  619. p->tos.tm = fz_pre_translate(p->tos.tm, tadj * gstate->pending.text.scale, 0);
  620. else
  621. p->tos.tm = fz_pre_translate(p->tos.tm, 0, tadj);
  622. }
  623. static void
  624. walk_string(fz_context *ctx, int uni, int remove, editable_str *str)
  625. {
  626. int rune;
  627. if (str->utf8 == NULL || str->pos == -1)
  628. return;
  629. do
  630. {
  631. char *s = &str->utf8[str->pos];
  632. size_t len;
  633. int n = fz_chartorune(&rune, s);
  634. if (rune == uni)
  635. {
  636. /* Match. Skip over that one. */
  637. }
  638. else if (uni == 32)
  639. {
  640. /* We don't care if we're given whitespace
  641. * and it doesn't match the string. Don't
  642. * skip forward. Nothing to remove. */
  643. break;
  644. }
  645. else if (rune == 32)
  646. {
  647. /* The string has a whitespace, and we
  648. * don't match it; that's forgivable as
  649. * PDF often misses out spaces. Remove this
  650. * if we are removing stuff. */
  651. }
  652. else
  653. {
  654. /* Mismatch. No point in tracking through any more. */
  655. str->pos = -1;
  656. break;
  657. }
  658. if (remove)
  659. {
  660. len = strlen(s+n);
  661. memmove(s, s+n, len+1);
  662. str->edited = 1;
  663. }
  664. else
  665. {
  666. str->pos += n;
  667. }
  668. }
  669. while (rune != uni);
  670. }
  671. /* For a given character we've processed (removed or not)
  672. * consider it in the tag_record. Try and step over it in
  673. * the Alt or ActualText strings, removing if possible.
  674. * If we can't marry up the Alt/ActualText strings with
  675. * what we're meeting, just take the easy route and delete
  676. * the whole lot. */
  677. static void
  678. mcid_char_imp(fz_context *ctx, pdf_sanitize_processor *p, tag_record *tr, int uni, int remove)
  679. {
  680. if (tr->mcid_obj == NULL)
  681. /* No object, or already deleted */
  682. return;
  683. if (remove)
  684. {
  685. /* Remove the expanded abbreviation, if there is one. */
  686. pdf_dict_del(ctx, tr->mcid_obj, PDF_NAME(E));
  687. /* Remove the structure title, if there is one. */
  688. pdf_dict_del(ctx, tr->mcid_obj, PDF_NAME(T));
  689. }
  690. /* Edit the Alt string */
  691. walk_string(ctx, uni, remove, &tr->alt);
  692. /* Edit the ActualText string */
  693. walk_string(ctx, uni, remove, &tr->actualtext);
  694. /* If we're removing a character, and either of the strings
  695. * haven't matched up to what we were expecting, then just
  696. * delete the whole string. */
  697. if (remove)
  698. remove = (tr->alt.pos == -1 || tr->actualtext.pos == -1);
  699. else if (tr->alt.pos >= 0 || tr->actualtext.pos >= 0)
  700. {
  701. /* The strings are making sense so far */
  702. remove = 0;
  703. }
  704. if (remove)
  705. {
  706. /* Anything else we have to err on the side of caution and
  707. * delete everything that might leak info. */
  708. if (tr->actualtext.pos == -1)
  709. pdf_dict_del(ctx, tr->mcid_obj, PDF_NAME(ActualText));
  710. if (tr->alt.pos == -1)
  711. pdf_dict_del(ctx, tr->mcid_obj, PDF_NAME(Alt));
  712. pdf_drop_obj(ctx, tr->mcid_obj);
  713. tr->mcid_obj = NULL;
  714. fz_free(ctx, tr->alt.utf8);
  715. tr->alt.utf8 = NULL;
  716. fz_free(ctx, tr->actualtext.utf8);
  717. tr->actualtext.utf8 = NULL;
  718. }
  719. }
  720. /* For every character that is processed, consider that character in
  721. * every pending/current MCID. */
  722. static void
  723. mcid_char(fz_context *ctx, pdf_sanitize_processor *p, int uni, int remove)
  724. {
  725. tag_record *tr = p->pending_tags;
  726. for (tr = p->pending_tags; tr != NULL; tr = tr->prev)
  727. mcid_char_imp(ctx, p, tr, uni, remove);
  728. for (tr = p->current_tags; tr != NULL; tr = tr->prev)
  729. mcid_char_imp(ctx, p, tr, uni, remove);
  730. }
  731. static void
  732. update_mcid(fz_context *ctx, pdf_sanitize_processor *p)
  733. {
  734. tag_record *tag = p->current_tags;
  735. if (tag == NULL)
  736. return;
  737. if (tag->mcid_obj == NULL)
  738. return;
  739. if (tag->alt.edited)
  740. pdf_dict_put_text_string(ctx, tag->mcid_obj, PDF_NAME(Alt), tag->alt.utf8 ? tag->alt.utf8 : "");
  741. if (tag->actualtext.edited)
  742. pdf_dict_put_text_string(ctx, tag->mcid_obj, PDF_NAME(Alt), tag->actualtext.utf8 ? tag->actualtext.utf8 : "");
  743. }
  744. /* Process a string (from buf, of length len), from position *pos onwards.
  745. * Stop when we hit the end, or when we find a character to remove. The
  746. * caller will restart us again later. On exit, *pos = the point we got to,
  747. * *inc = The number of bytes to skip to step over the next character (unless
  748. * we hit the end).
  749. */
  750. static void
  751. filter_string_to_segment(fz_context *ctx, pdf_sanitize_processor *p, unsigned char *buf, size_t len, size_t *pos, int *inc, int *removed_space)
  752. {
  753. filter_gstate *gstate = p->gstate;
  754. pdf_font_desc *fontdesc = gstate->pending.text.font;
  755. unsigned char *end = buf + len;
  756. unsigned int cpt;
  757. int cid;
  758. int remove;
  759. buf += *pos;
  760. *removed_space = 0;
  761. while (buf < end)
  762. {
  763. int uni;
  764. *inc = pdf_decode_cmap(fontdesc->encoding, buf, end, &cpt);
  765. buf += *inc;
  766. cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
  767. if (cid < 0)
  768. {
  769. uni = FZ_REPLACEMENT_CHARACTER;
  770. fz_warn(ctx, "cannot encode character");
  771. remove = 0;
  772. }
  773. else
  774. remove = filter_show_char(ctx, p, cid, &uni);
  775. /* FIXME: Should check for marking/non-marking! For
  776. * now assume space is the only non-marking. */
  777. if (cpt != 32)
  778. {
  779. if (remove)
  780. p->text_removed = 1;
  781. else
  782. p->text_sent = 1;
  783. }
  784. if (cpt == 32 && *inc == 1)
  785. filter_show_space(ctx, p, gstate->pending.text.word_space);
  786. /* For every character we process (whether we remove it
  787. * or not), we consider any MCIDs that are in effect. */
  788. mcid_char(ctx, p, uni, remove);
  789. if (remove)
  790. {
  791. *removed_space = (cpt == 32 && *inc == 1);
  792. return;
  793. }
  794. *pos += *inc;
  795. }
  796. }
  797. static void
  798. adjust_text(fz_context *ctx, pdf_sanitize_processor *p, float x, float y)
  799. {
  800. float skip_dist = p->tos.fontdesc->wmode == 1 ? -y : -x;
  801. skip_dist = skip_dist / p->gstate->pending.text.size;
  802. p->Tm_adjust += skip_dist;
  803. }
  804. static void
  805. adjust_for_removed_space(fz_context *ctx, pdf_sanitize_processor *p)
  806. {
  807. filter_gstate *gstate = p->gstate;
  808. float adj = gstate->pending.text.word_space;
  809. adjust_text(ctx, p, adj, adj);
  810. }
  811. static void
  812. flush_adjustment(fz_context *ctx, pdf_sanitize_processor *p)
  813. {
  814. pdf_obj *arr;
  815. if (p->Tm_adjust == 0)
  816. return;
  817. filter_flush(ctx, p, FLUSH_ALL);
  818. arr = pdf_new_array(ctx, p->doc, 1);
  819. fz_try(ctx)
  820. {
  821. pdf_array_push_real(ctx, arr, p->Tm_adjust * 1000);
  822. if (p->chain->op_TJ)
  823. p->chain->op_TJ(ctx, p->chain, arr);
  824. }
  825. fz_always(ctx)
  826. pdf_drop_obj(ctx, arr);
  827. fz_catch(ctx)
  828. fz_rethrow(ctx);
  829. p->Tm_adjust = 0;
  830. }
  831. static void
  832. push_adjustment_to_array(fz_context *ctx, pdf_sanitize_processor *p, pdf_obj *arr)
  833. {
  834. if (p->Tm_adjust == 0)
  835. return;
  836. pdf_array_push_real(ctx, arr, p->Tm_adjust * 1000);
  837. p->Tm_adjust = 0;
  838. }
  839. static void
  840. filter_show_string(fz_context *ctx, pdf_sanitize_processor *p, unsigned char *buf, size_t len)
  841. {
  842. filter_gstate *gstate = p->gstate;
  843. pdf_font_desc *fontdesc = gstate->pending.text.font;
  844. int inc, removed_space;
  845. size_t i;
  846. if (!fontdesc)
  847. return;
  848. p->tos.fontdesc = fontdesc;
  849. i = 0;
  850. while (i < len)
  851. {
  852. size_t start = i;
  853. filter_string_to_segment(ctx, p, buf, len, &i, &inc, &removed_space);
  854. if (start != i)
  855. {
  856. /* We have *some* chars to send at least */
  857. filter_flush(ctx, p, FLUSH_ALL);
  858. flush_adjustment(ctx, p);
  859. if (p->chain->op_Tj)
  860. p->chain->op_Tj(ctx, p->chain, (char *)buf+start, i-start);
  861. }
  862. if (i != len)
  863. {
  864. adjust_text(ctx, p, p->tos.char_tx / p->gstate->pending.text.scale, p->tos.char_ty);
  865. i += inc;
  866. }
  867. if (removed_space)
  868. adjust_for_removed_space(ctx, p);
  869. }
  870. }
  871. static void
  872. filter_show_text(fz_context *ctx, pdf_sanitize_processor *p, pdf_obj *text)
  873. {
  874. filter_gstate *gstate = p->gstate;
  875. pdf_font_desc *fontdesc = gstate->pending.text.font;
  876. int i, n;
  877. pdf_obj *new_arr;
  878. pdf_document *doc;
  879. if (!fontdesc)
  880. return;
  881. if (pdf_is_string(ctx, text))
  882. {
  883. filter_show_string(ctx, p, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text));
  884. return;
  885. }
  886. if (!pdf_is_array(ctx, text))
  887. return;
  888. p->tos.fontdesc = fontdesc;
  889. n = pdf_array_len(ctx, text);
  890. doc = pdf_get_bound_document(ctx, text);
  891. new_arr = pdf_new_array(ctx, doc, 4);
  892. fz_try(ctx)
  893. {
  894. for (i = 0; i < n; i++)
  895. {
  896. pdf_obj *item = pdf_array_get(ctx, text, i);
  897. if (pdf_is_string(ctx, item))
  898. {
  899. unsigned char *buf = (unsigned char *)pdf_to_str_buf(ctx, item);
  900. size_t len = pdf_to_str_len(ctx, item);
  901. size_t j = 0;
  902. int removed_space;
  903. while (j < len)
  904. {
  905. int inc;
  906. size_t start = j;
  907. filter_string_to_segment(ctx, p, buf, len, &j, &inc, &removed_space);
  908. if (start != j)
  909. {
  910. /* We have *some* chars to send at least */
  911. filter_flush(ctx, p, FLUSH_ALL);
  912. push_adjustment_to_array(ctx, p, new_arr);
  913. pdf_array_push_string(ctx, new_arr, (char *)buf+start, j-start);
  914. }
  915. if (j != len)
  916. {
  917. adjust_text(ctx, p, p->tos.char_tx / p->gstate->pending.text.scale, p->tos.char_ty);
  918. j += inc;
  919. }
  920. if (removed_space)
  921. adjust_for_removed_space(ctx, p);
  922. }
  923. }
  924. else
  925. {
  926. float tadj = - pdf_to_real(ctx, item) * gstate->pending.text.size * 0.001f;
  927. if (fontdesc->wmode == 0)
  928. {
  929. adjust_text(ctx, p, tadj, 0);
  930. p->tos.tm = fz_pre_translate(p->tos.tm, tadj * p->gstate->pending.text.scale, 0);
  931. }
  932. else
  933. {
  934. adjust_text(ctx, p, 0, tadj);
  935. p->tos.tm = fz_pre_translate(p->tos.tm, 0, tadj);
  936. }
  937. }
  938. }
  939. if (p->chain->op_TJ && pdf_array_len(ctx, new_arr))
  940. p->chain->op_TJ(ctx, p->chain, new_arr);
  941. }
  942. fz_always(ctx)
  943. pdf_drop_obj(ctx, new_arr);
  944. fz_catch(ctx)
  945. fz_rethrow(ctx);
  946. }
  947. /* general graphics state */
  948. static void
  949. pdf_filter_w(fz_context *ctx, pdf_processor *proc, float linewidth)
  950. {
  951. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  952. filter_gstate *gstate = p->gstate;
  953. if (fz_is_empty_rect(p->gstate->clip_rect))
  954. return;
  955. gstate->pending.stroke.linewidth = linewidth;
  956. }
  957. static void
  958. pdf_filter_j(fz_context *ctx, pdf_processor *proc, int linejoin)
  959. {
  960. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  961. filter_gstate *gstate = p->gstate;
  962. if (fz_is_empty_rect(p->gstate->clip_rect))
  963. return;
  964. gstate->pending.stroke.linejoin = linejoin;
  965. }
  966. static void
  967. pdf_filter_J(fz_context *ctx, pdf_processor *proc, int linecap)
  968. {
  969. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  970. filter_gstate *gstate = p->gstate;
  971. if (fz_is_empty_rect(p->gstate->clip_rect))
  972. return;
  973. gstate->pending.stroke.linecap = linecap;
  974. }
  975. static void
  976. pdf_filter_M(fz_context *ctx, pdf_processor *proc, float miterlimit)
  977. {
  978. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  979. filter_gstate *gstate = p->gstate;
  980. if (fz_is_empty_rect(p->gstate->clip_rect))
  981. return;
  982. gstate->pending.stroke.miterlimit = miterlimit;
  983. }
  984. static void
  985. pdf_filter_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase)
  986. {
  987. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  988. if (fz_is_empty_rect(p->gstate->clip_rect))
  989. return;
  990. filter_flush(ctx, p, FLUSH_OP);
  991. if (p->chain->op_d)
  992. p->chain->op_d(ctx, p->chain, array, phase);
  993. }
  994. static void
  995. pdf_filter_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
  996. {
  997. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  998. if (fz_is_empty_rect(p->gstate->clip_rect))
  999. return;
  1000. filter_flush(ctx, p, FLUSH_OP);
  1001. if (p->chain->op_ri)
  1002. p->chain->op_ri(ctx, p->chain, intent);
  1003. }
  1004. static void
  1005. pdf_filter_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
  1006. {
  1007. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1008. if (fz_is_empty_rect(p->gstate->clip_rect))
  1009. return;
  1010. filter_flush(ctx, p, FLUSH_OP);
  1011. if (p->chain->op_gs_OP)
  1012. p->chain->op_gs_OP(ctx, p->chain, b);
  1013. }
  1014. static void
  1015. pdf_filter_gs_op(fz_context *ctx, pdf_processor *proc, int b)
  1016. {
  1017. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1018. if (fz_is_empty_rect(p->gstate->clip_rect))
  1019. return;
  1020. filter_flush(ctx, p, FLUSH_OP);
  1021. if (p->chain->op_gs_op)
  1022. p->chain->op_gs_op(ctx, p->chain, b);
  1023. }
  1024. static void
  1025. pdf_filter_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
  1026. {
  1027. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1028. if (fz_is_empty_rect(p->gstate->clip_rect))
  1029. return;
  1030. filter_flush(ctx, p, FLUSH_OP);
  1031. if (p->chain->op_gs_OPM)
  1032. p->chain->op_gs_OPM(ctx, p->chain, i);
  1033. }
  1034. static void
  1035. pdf_filter_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name)
  1036. {
  1037. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1038. if (fz_is_empty_rect(p->gstate->clip_rect))
  1039. return;
  1040. filter_flush(ctx, p, FLUSH_OP);
  1041. if (p->chain->op_gs_UseBlackPtComp)
  1042. p->chain->op_gs_UseBlackPtComp(ctx, p->chain, name);
  1043. }
  1044. static void
  1045. pdf_filter_i(fz_context *ctx, pdf_processor *proc, float flatness)
  1046. {
  1047. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1048. if (fz_is_empty_rect(p->gstate->clip_rect))
  1049. return;
  1050. filter_flush(ctx, p, FLUSH_OP);
  1051. if (p->chain->op_i)
  1052. p->chain->op_i(ctx, p->chain, flatness);
  1053. }
  1054. static void
  1055. pdf_filter_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
  1056. {
  1057. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1058. if (fz_is_empty_rect(p->gstate->clip_rect))
  1059. return;
  1060. filter_flush(ctx, p, FLUSH_ALL | FLUSH_OP);
  1061. if (p->chain->op_gs_begin)
  1062. p->chain->op_gs_begin(ctx, p->chain, name, extgstate);
  1063. copy_resource(ctx, p, PDF_NAME(ExtGState), name);
  1064. }
  1065. static void
  1066. pdf_filter_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode)
  1067. {
  1068. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1069. if (fz_is_empty_rect(p->gstate->clip_rect))
  1070. return;
  1071. if (p->chain->op_gs_BM)
  1072. p->chain->op_gs_BM(ctx, p->chain, blendmode);
  1073. }
  1074. static void
  1075. pdf_filter_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha)
  1076. {
  1077. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1078. if (fz_is_empty_rect(p->gstate->clip_rect))
  1079. return;
  1080. if (p->chain->op_gs_CA)
  1081. p->chain->op_gs_CA(ctx, p->chain, alpha);
  1082. }
  1083. static void
  1084. pdf_filter_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha)
  1085. {
  1086. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1087. if (fz_is_empty_rect(p->gstate->clip_rect))
  1088. return;
  1089. if (p->chain->op_gs_ca)
  1090. p->chain->op_gs_ca(ctx, p->chain, alpha);
  1091. }
  1092. static void
  1093. pdf_filter_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, fz_colorspace *smask_cs, float *bc, int luminosity, pdf_obj *tr)
  1094. {
  1095. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1096. if (fz_is_empty_rect(p->gstate->clip_rect))
  1097. return;
  1098. if (p->chain->op_gs_SMask)
  1099. p->chain->op_gs_SMask(ctx, p->chain, smask, smask_cs, bc, luminosity, tr);
  1100. }
  1101. static void
  1102. pdf_filter_gs_end(fz_context *ctx, pdf_processor *proc)
  1103. {
  1104. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1105. if (fz_is_empty_rect(p->gstate->clip_rect))
  1106. return;
  1107. if (p->chain->op_gs_end)
  1108. p->chain->op_gs_end(ctx, p->chain);
  1109. }
  1110. /* special graphics state */
  1111. static void
  1112. pdf_filter_q(fz_context *ctx, pdf_processor *proc)
  1113. {
  1114. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1115. filter_push(ctx, p);
  1116. }
  1117. static void
  1118. pdf_filter_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
  1119. {
  1120. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1121. filter_gstate *gstate = p->gstate;
  1122. fz_matrix ctm;
  1123. if (fz_is_empty_rect(p->gstate->clip_rect))
  1124. return;
  1125. /* If we're being given an identity matrix, don't bother sending it */
  1126. if (a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0)
  1127. return;
  1128. ctm.a = a;
  1129. ctm.b = b;
  1130. ctm.c = c;
  1131. ctm.d = d;
  1132. ctm.e = e;
  1133. ctm.f = f;
  1134. gstate->pending.ctm = fz_concat(ctm, gstate->pending.ctm);
  1135. }
  1136. /* path construction */
  1137. static void
  1138. pdf_filter_m(fz_context *ctx, pdf_processor *proc, float x, float y)
  1139. {
  1140. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1141. if (fz_is_empty_rect(p->gstate->clip_rect))
  1142. return;
  1143. fz_moveto(ctx, p->path, x, y);
  1144. }
  1145. static void
  1146. pdf_filter_l(fz_context *ctx, pdf_processor *proc, float x, float y)
  1147. {
  1148. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1149. if (fz_is_empty_rect(p->gstate->clip_rect))
  1150. return;
  1151. fz_lineto(ctx, p->path, x, y);
  1152. }
  1153. static void
  1154. pdf_filter_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3)
  1155. {
  1156. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1157. if (fz_is_empty_rect(p->gstate->clip_rect))
  1158. return;
  1159. fz_curveto(ctx, p->path, x1, y1, x2, y2, x3, y3);
  1160. }
  1161. static void
  1162. pdf_filter_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3)
  1163. {
  1164. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1165. if (fz_is_empty_rect(p->gstate->clip_rect))
  1166. return;
  1167. fz_curvetov(ctx, p->path, x2, y2, x3, y3);
  1168. }
  1169. static void
  1170. pdf_filter_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3)
  1171. {
  1172. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1173. if (fz_is_empty_rect(p->gstate->clip_rect))
  1174. return;
  1175. fz_curvetoy(ctx, p->path, x1, y1, x3, y3);
  1176. }
  1177. static void
  1178. pdf_filter_h(fz_context *ctx, pdf_processor *proc)
  1179. {
  1180. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1181. if (fz_is_empty_rect(p->gstate->clip_rect))
  1182. return;
  1183. fz_closepath(ctx, p->path);
  1184. }
  1185. static void
  1186. pdf_filter_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
  1187. {
  1188. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1189. if (fz_is_empty_rect(p->gstate->clip_rect))
  1190. return;
  1191. fz_rectto(ctx, p->path, x, y, x+w, y+h);
  1192. }
  1193. /* path painting */
  1194. static void
  1195. cull_replay_moveto(fz_context *ctx, void *arg, float x, float y)
  1196. {
  1197. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1198. if (p->chain->op_m)
  1199. p->chain->op_m(ctx, p->chain, x, y);
  1200. }
  1201. static void cull_replay_lineto(fz_context *ctx, void *arg, float x, float y)
  1202. {
  1203. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1204. if (p->chain->op_l)
  1205. p->chain->op_l(ctx, p->chain, x, y);
  1206. }
  1207. static void
  1208. cull_replay_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
  1209. {
  1210. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1211. if (p->chain->op_c)
  1212. p->chain->op_c(ctx, p->chain, x1, y1, x2, y2, x3, y3);
  1213. }
  1214. static void
  1215. cull_replay_closepath(fz_context *ctx, void *arg)
  1216. {
  1217. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1218. if (p->chain->op_h)
  1219. p->chain->op_h(ctx, p->chain);
  1220. }
  1221. static void
  1222. cull_replay_curvetov(fz_context *ctx, void *arg, float x2, float y2, float x3, float y3)
  1223. {
  1224. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1225. if (p->chain->op_v)
  1226. p->chain->op_v(ctx, p->chain, x2, y2, x3, y3);
  1227. }
  1228. static void
  1229. cull_replay_curvetoy(fz_context *ctx, void *arg, float x1, float y1, float x3, float y3)
  1230. {
  1231. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1232. if (p->chain->op_y)
  1233. p->chain->op_y(ctx, p->chain, x1, y1, x3, y3);
  1234. }
  1235. static void
  1236. cull_replay_rectto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2)
  1237. {
  1238. pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
  1239. if (p->chain->op_re)
  1240. p->chain->op_re(ctx, p->chain, x1, y1, x2-x1, y2-y1);
  1241. }
  1242. typedef struct
  1243. {
  1244. pdf_sanitize_processor *p;
  1245. fz_stroke_state *sstate;
  1246. fz_path *segment;
  1247. fz_matrix ctm;
  1248. int any_sent;
  1249. int type;
  1250. int flush;
  1251. } segmenter_data_t;
  1252. static const fz_path_walker cull_replay_walker = {
  1253. cull_replay_moveto,
  1254. cull_replay_lineto,
  1255. cull_replay_curveto,
  1256. cull_replay_closepath,
  1257. NULL /* quad */,
  1258. cull_replay_curvetov,
  1259. cull_replay_curvetoy,
  1260. cull_replay_rectto
  1261. };
  1262. static void
  1263. end_segment(fz_context *ctx, segmenter_data_t *sd)
  1264. {
  1265. fz_rect r;
  1266. const fz_stroke_state *st;
  1267. if (sd->segment == NULL)
  1268. return;
  1269. st = (sd->type == FZ_CULL_PATH_STROKE || sd->type == FZ_CULL_PATH_FILL_STROKE) ? sd->sstate : NULL;
  1270. r = fz_bound_path(ctx, sd->segment, st, sd->ctm);
  1271. if (sd->p->options->culler && sd->p->options->culler(ctx, sd->p->options->opaque, r, sd->type))
  1272. {
  1273. /* This segment can be skipped */
  1274. }
  1275. else
  1276. {
  1277. /* Better send this segment then! */
  1278. /* Flush, just once, at the last possible minute. */
  1279. if (sd->flush)
  1280. {
  1281. filter_flush(ctx, sd->p, sd->flush);
  1282. sd->flush = 0;
  1283. }
  1284. fz_walk_path(ctx, sd->segment, &cull_replay_walker, sd->p);
  1285. sd->any_sent = 1;
  1286. }
  1287. fz_drop_path(ctx, sd->segment);
  1288. sd->segment = NULL;
  1289. }
  1290. static void
  1291. cull_segmenter_moveto(fz_context *ctx, void *arg, float x, float y)
  1292. {
  1293. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1294. end_segment(ctx, sd);
  1295. sd->segment = fz_new_path(ctx);
  1296. fz_moveto(ctx, sd->segment, x, y);
  1297. }
  1298. static void
  1299. cull_segmenter_lineto(fz_context *ctx, void *arg, float x, float y)
  1300. {
  1301. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1302. fz_lineto(ctx, sd->segment, x, y);
  1303. }
  1304. static void
  1305. cull_segmenter_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
  1306. {
  1307. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1308. fz_curveto(ctx, sd->segment, x1, y1, x2, y2, x3, y3);
  1309. }
  1310. static void
  1311. cull_segmenter_closepath(fz_context *ctx, void *arg)
  1312. {
  1313. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1314. fz_closepath(ctx, sd->segment);
  1315. }
  1316. static void
  1317. cull_segmenter_curvetov(fz_context *ctx, void *arg, float x2, float y2, float x3, float y3)
  1318. {
  1319. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1320. fz_curvetov(ctx, sd->segment, x2, y2, x3, y3);
  1321. }
  1322. static void
  1323. cull_segmenter_curvetoy(fz_context *ctx, void *arg, float x1, float y1, float x3, float y3)
  1324. {
  1325. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1326. fz_curvetoy(ctx, sd->segment, x1, y1, x3, y3);
  1327. }
  1328. static void
  1329. cull_segmenter_rectto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2)
  1330. {
  1331. segmenter_data_t *sd = (segmenter_data_t *)arg;
  1332. end_segment(ctx, sd);
  1333. sd->segment = fz_new_path(ctx);
  1334. fz_rectto(ctx, sd->segment, x1, y1, x2, y2);
  1335. }
  1336. static int
  1337. cull_path(fz_context *ctx, pdf_sanitize_processor *p, int type, int flush)
  1338. {
  1339. segmenter_data_t sd = { 0 };
  1340. static const fz_path_walker segmenter = {
  1341. cull_segmenter_moveto,
  1342. cull_segmenter_lineto,
  1343. cull_segmenter_curveto,
  1344. cull_segmenter_closepath,
  1345. NULL /* quad */,
  1346. cull_segmenter_curvetov,
  1347. cull_segmenter_curvetoy,
  1348. cull_segmenter_rectto
  1349. };
  1350. if (p->options->culler == NULL)
  1351. {
  1352. filter_flush(ctx, p, flush | FLUSH_OP);
  1353. fz_walk_path(ctx, p->path, &cull_replay_walker, p);
  1354. if (p->gstate->clip_op != NO_CLIP_OP)
  1355. {
  1356. fz_rect r;
  1357. /* ctm has always been flushed by now. */
  1358. r = fz_bound_path(ctx, p->path, NULL, p->gstate->sent.ctm);
  1359. p->gstate->clip_rect = fz_intersect_rect(p->gstate->clip_rect, r);
  1360. if (p->gstate->clip_op == CLIP_W)
  1361. {
  1362. if (p->chain->op_W)
  1363. p->chain->op_W(ctx, p->chain);
  1364. }
  1365. else
  1366. {
  1367. if (p->chain->op_Wstar)
  1368. p->chain->op_Wstar(ctx, p->chain);
  1369. }
  1370. p->gstate->clip_op = NO_CLIP_OP;
  1371. }
  1372. fz_drop_path(ctx, p->path);
  1373. p->path = NULL;
  1374. p->path = fz_new_path(ctx);
  1375. return 0;
  1376. }
  1377. sd.ctm = fz_concat(p->gstate->pending.ctm, p->gstate->sent.ctm);
  1378. sd.ctm = fz_concat(sd.ctm, p->transform);
  1379. if (type == FZ_CULL_PATH_STROKE || type == FZ_CULL_PATH_FILL_STROKE)
  1380. {
  1381. sd.sstate = fz_new_stroke_state(ctx);
  1382. sd.sstate->start_cap = p->gstate->pending.stroke.linecap;
  1383. sd.sstate->dash_cap = p->gstate->pending.stroke.linecap;
  1384. sd.sstate->end_cap = p->gstate->pending.stroke.linecap;
  1385. sd.sstate->linejoin = p->gstate->pending.stroke.linejoin;
  1386. sd.sstate->linewidth = p->gstate->pending.stroke.linewidth;
  1387. sd.sstate->miterlimit = p->gstate->pending.stroke.miterlimit;
  1388. /* Ignore dash for now. */
  1389. }
  1390. sd.p = p;
  1391. sd.segment = NULL;
  1392. sd.type = type;
  1393. if (p->gstate->clip_op != NO_CLIP_OP)
  1394. sd.type += FZ_CULL_CLIP_PATH_FILL - FZ_CULL_PATH_FILL;
  1395. sd.flush = flush | FLUSH_OP;
  1396. fz_try(ctx)
  1397. {
  1398. fz_walk_path(ctx, p->path, &segmenter, &sd);
  1399. end_segment(ctx, &sd);
  1400. }
  1401. fz_always(ctx)
  1402. {
  1403. fz_drop_path(ctx, sd.segment);
  1404. fz_drop_stroke_state(ctx, sd.sstate);
  1405. }
  1406. fz_catch(ctx)
  1407. fz_rethrow(ctx);
  1408. if (sd.any_sent != 0 && p->gstate->clip_op != NO_CLIP_OP)
  1409. {
  1410. fz_rect r;
  1411. /* ctm has always been flushed by now. */
  1412. r = fz_bound_path(ctx, p->path, NULL, p->gstate->sent.ctm);
  1413. p->gstate->clip_rect = fz_intersect_rect(p->gstate->clip_rect, r);
  1414. if (p->gstate->clip_op == CLIP_W)
  1415. {
  1416. if (p->chain->op_W)
  1417. p->chain->op_W(ctx, p->chain);
  1418. }
  1419. else
  1420. {
  1421. if (p->chain->op_Wstar)
  1422. p->chain->op_Wstar(ctx, p->chain);
  1423. }
  1424. p->gstate->clip_op = NO_CLIP_OP;
  1425. }
  1426. fz_drop_path(ctx, p->path);
  1427. p->path = NULL;
  1428. p->path = fz_new_path(ctx);
  1429. /* If none were sent, we can skip this path. */
  1430. return (sd.any_sent == 0);
  1431. }
  1432. static void
  1433. pdf_filter_S(fz_context *ctx, pdf_processor *proc)
  1434. {
  1435. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1436. if (fz_is_empty_rect(p->gstate->clip_rect))
  1437. return;
  1438. if (cull_path(ctx, p, FZ_CULL_PATH_STROKE, FLUSH_STROKE))
  1439. return;
  1440. if (p->chain->op_S)
  1441. p->chain->op_S(ctx, p->chain);
  1442. }
  1443. static void
  1444. pdf_filter_s(fz_context *ctx, pdf_processor *proc)
  1445. {
  1446. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1447. if (fz_is_empty_rect(p->gstate->clip_rect))
  1448. return;
  1449. if (cull_path(ctx, p, FZ_CULL_PATH_STROKE, FLUSH_STROKE))
  1450. return;
  1451. if (p->chain->op_s)
  1452. p->chain->op_s(ctx, p->chain);
  1453. }
  1454. static void
  1455. pdf_filter_F(fz_context *ctx, pdf_processor *proc)
  1456. {
  1457. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1458. if (fz_is_empty_rect(p->gstate->clip_rect))
  1459. return;
  1460. if (cull_path(ctx, p, FZ_CULL_PATH_FILL, FLUSH_FILL))
  1461. return;
  1462. if (p->chain->op_F)
  1463. p->chain->op_F(ctx, p->chain);
  1464. }
  1465. static void
  1466. pdf_filter_f(fz_context *ctx, pdf_processor *proc)
  1467. {
  1468. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1469. if (fz_is_empty_rect(p->gstate->clip_rect))
  1470. return;
  1471. if (cull_path(ctx, p, FZ_CULL_PATH_FILL, FLUSH_FILL))
  1472. return;
  1473. if (p->chain->op_f)
  1474. p->chain->op_f(ctx, p->chain);
  1475. }
  1476. static void
  1477. pdf_filter_fstar(fz_context *ctx, pdf_processor *proc)
  1478. {
  1479. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1480. if (fz_is_empty_rect(p->gstate->clip_rect))
  1481. return;
  1482. if (cull_path(ctx, p, FZ_CULL_PATH_FILL, FLUSH_FILL))
  1483. return;
  1484. if (p->chain->op_fstar)
  1485. p->chain->op_fstar(ctx, p->chain);
  1486. }
  1487. static void
  1488. pdf_filter_B(fz_context *ctx, pdf_processor *proc)
  1489. {
  1490. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1491. if (fz_is_empty_rect(p->gstate->clip_rect))
  1492. return;
  1493. if (cull_path(ctx, p, FZ_CULL_PATH_FILL_STROKE, FLUSH_ALL))
  1494. return;
  1495. if (p->chain->op_B)
  1496. p->chain->op_B(ctx, p->chain);
  1497. }
  1498. static void
  1499. pdf_filter_Bstar(fz_context *ctx, pdf_processor *proc)
  1500. {
  1501. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1502. if (fz_is_empty_rect(p->gstate->clip_rect))
  1503. return;
  1504. if (cull_path(ctx, p, FZ_CULL_PATH_FILL_STROKE, FLUSH_ALL))
  1505. return;
  1506. if (p->chain->op_Bstar)
  1507. p->chain->op_Bstar(ctx, p->chain);
  1508. }
  1509. static void
  1510. pdf_filter_b(fz_context *ctx, pdf_processor *proc)
  1511. {
  1512. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1513. if (fz_is_empty_rect(p->gstate->clip_rect))
  1514. return;
  1515. if (cull_path(ctx, p, FZ_CULL_PATH_FILL_STROKE, FLUSH_ALL))
  1516. return;
  1517. if (p->chain->op_b)
  1518. p->chain->op_b(ctx, p->chain);
  1519. }
  1520. static void
  1521. pdf_filter_bstar(fz_context *ctx, pdf_processor *proc)
  1522. {
  1523. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1524. if (fz_is_empty_rect(p->gstate->clip_rect))
  1525. return;
  1526. if (cull_path(ctx, p, FZ_CULL_PATH_FILL_STROKE, FLUSH_ALL))
  1527. return;
  1528. if (p->chain->op_bstar)
  1529. p->chain->op_bstar(ctx, p->chain);
  1530. }
  1531. static void
  1532. pdf_filter_n(fz_context *ctx, pdf_processor *proc)
  1533. {
  1534. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1535. if (fz_is_empty_rect(p->gstate->clip_rect))
  1536. return;
  1537. if (cull_path(ctx, p, FZ_CULL_PATH_DROP, FLUSH_ALL))
  1538. return;
  1539. if (p->chain->op_n)
  1540. p->chain->op_n(ctx, p->chain);
  1541. }
  1542. /* clipping paths */
  1543. static void
  1544. pdf_filter_W(fz_context *ctx, pdf_processor *proc)
  1545. {
  1546. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1547. if (fz_is_empty_rect(p->gstate->clip_rect))
  1548. return;
  1549. /* This operator does nothing when it is seen. It just affects the
  1550. * behaviour of the subsequent path drawing operation. */
  1551. p->gstate->clip_op = CLIP_W;
  1552. }
  1553. static void
  1554. pdf_filter_Wstar(fz_context *ctx, pdf_processor *proc)
  1555. {
  1556. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1557. if (fz_is_empty_rect(p->gstate->clip_rect))
  1558. return;
  1559. /* This operator does nothing when it is seen. It just affects the
  1560. * behaviour of the subsequent path drawing operation. */
  1561. p->gstate->clip_op = CLIP_Wstar;
  1562. }
  1563. /* text objects */
  1564. static void
  1565. pdf_filter_BT(fz_context *ctx, pdf_processor *proc)
  1566. {
  1567. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1568. if (fz_is_empty_rect(p->gstate->clip_rect))
  1569. return;
  1570. filter_flush(ctx, p, 0);
  1571. p->tos.tm = fz_identity;
  1572. p->tos.tlm = fz_identity;
  1573. p->BT_pending = 1;
  1574. p->text_sent = 0;
  1575. p->text_removed = 0;
  1576. p->Td_pending = 0;
  1577. p->Td_value.x = p->Td_value.y = 0;
  1578. }
  1579. static void
  1580. pdf_filter_ET(fz_context *ctx, pdf_processor *proc)
  1581. {
  1582. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1583. if (fz_is_empty_rect(p->gstate->clip_rect))
  1584. return;
  1585. if (!p->BT_pending)
  1586. {
  1587. filter_flush(ctx, p, FLUSH_OP);
  1588. if (p->chain->op_ET)
  1589. p->chain->op_ET(ctx, p->chain);
  1590. p->in_BT = 0;
  1591. }
  1592. if ((p->gstate->pending.text.render & 4) && p->text_removed && !p->text_sent)
  1593. {
  1594. /* We've just had an empty (or non-marking) BT/ET, where clipping is
  1595. * enabled, and previously it was non-empty. This means we've changed
  1596. * it from a finite clip path, to something that doesn't change the
  1597. * clip path at all. We actually want it to be an empty clip path,
  1598. * but we can't easily achieve that. So we have to do the clipping
  1599. * ourselves. */
  1600. p->gstate->clip_rect = fz_empty_rect;
  1601. }
  1602. p->BT_pending = 0;
  1603. if (p->options->after_text_object)
  1604. {
  1605. fz_matrix ctm;
  1606. ctm = fz_concat(p->gstate->pending.ctm, p->gstate->sent.ctm);
  1607. ctm = fz_concat(ctm, p->transform);
  1608. if (p->chain->op_q)
  1609. p->chain->op_q(ctx, p->chain);
  1610. p->options->after_text_object(ctx, p->options->opaque, p->doc, p->chain, ctm);
  1611. if (p->chain->op_Q)
  1612. p->chain->op_Q(ctx, p->chain);
  1613. }
  1614. }
  1615. static void
  1616. pdf_filter_Q(fz_context *ctx, pdf_processor *proc)
  1617. {
  1618. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1619. filter_flush(ctx, p, FLUSH_TEXT);
  1620. if (p->in_BT)
  1621. pdf_filter_ET(ctx, proc);
  1622. filter_pop(ctx, p);
  1623. }
  1624. /* text state */
  1625. static void
  1626. pdf_filter_Tc(fz_context *ctx, pdf_processor *proc, float charspace)
  1627. {
  1628. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1629. if (fz_is_empty_rect(p->gstate->clip_rect))
  1630. return;
  1631. filter_flush(ctx, p, FLUSH_OP);
  1632. p->gstate->pending.text.char_space = charspace;
  1633. }
  1634. static void
  1635. pdf_filter_Tw(fz_context *ctx, pdf_processor *proc, float wordspace)
  1636. {
  1637. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1638. if (fz_is_empty_rect(p->gstate->clip_rect))
  1639. return;
  1640. filter_flush(ctx, p, FLUSH_OP);
  1641. p->gstate->pending.text.word_space = wordspace;
  1642. }
  1643. static void
  1644. pdf_filter_Tz(fz_context *ctx, pdf_processor *proc, float scale)
  1645. {
  1646. /* scale is as written in the file. It is 100 times smaller
  1647. * in the gstate. */
  1648. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1649. if (fz_is_empty_rect(p->gstate->clip_rect))
  1650. return;
  1651. filter_flush(ctx, p, FLUSH_OP);
  1652. p->gstate->pending.text.scale = scale / 100;
  1653. }
  1654. static void
  1655. pdf_filter_TL(fz_context *ctx, pdf_processor *proc, float leading)
  1656. {
  1657. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1658. if (fz_is_empty_rect(p->gstate->clip_rect))
  1659. return;
  1660. filter_flush(ctx, p, FLUSH_OP);
  1661. p->gstate->pending.text.leading = leading;
  1662. }
  1663. static void
  1664. pdf_filter_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size)
  1665. {
  1666. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1667. if (fz_is_empty_rect(p->gstate->clip_rect))
  1668. return;
  1669. filter_flush(ctx, p, FLUSH_OP);
  1670. fz_drop_string(ctx, p->gstate->pending.text.fontname);
  1671. p->gstate->pending.text.fontname = NULL;
  1672. p->gstate->pending.text.fontname = name ? fz_new_string(ctx, name) : NULL;
  1673. pdf_drop_font(ctx, p->gstate->pending.text.font);
  1674. p->gstate->pending.text.font = pdf_keep_font(ctx, font);
  1675. p->gstate->pending.text.size = size;
  1676. copy_resource(ctx, p, PDF_NAME(Font), name);
  1677. }
  1678. static void
  1679. pdf_filter_Tr(fz_context *ctx, pdf_processor *proc, int render)
  1680. {
  1681. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1682. if (fz_is_empty_rect(p->gstate->clip_rect))
  1683. return;
  1684. filter_flush(ctx, p, FLUSH_OP);
  1685. p->gstate->pending.text.render = render;
  1686. }
  1687. static void
  1688. pdf_filter_Ts(fz_context *ctx, pdf_processor *proc, float rise)
  1689. {
  1690. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1691. if (fz_is_empty_rect(p->gstate->clip_rect))
  1692. return;
  1693. filter_flush(ctx, p, FLUSH_OP);
  1694. p->gstate->pending.text.rise = rise;
  1695. }
  1696. /* text positioning */
  1697. static void
  1698. pdf_filter_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty)
  1699. {
  1700. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1701. if (fz_is_empty_rect(p->gstate->clip_rect))
  1702. return;
  1703. p->Tm_adjust = 0;
  1704. pdf_tos_translate(&p->tos, tx, ty);
  1705. if (p->Tm_pending)
  1706. return; /* Exit, just with Tm_pending */
  1707. if (p->Td_pending)
  1708. tx += p->Td_value.x, ty += p->Td_value.y;
  1709. p->Td_value.x = tx;
  1710. p->Td_value.y = ty;
  1711. p->Td_pending = 1;
  1712. }
  1713. static void
  1714. pdf_filter_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty)
  1715. {
  1716. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1717. if (fz_is_empty_rect(p->gstate->clip_rect))
  1718. return;
  1719. p->gstate->pending.text.leading = -ty;
  1720. pdf_filter_Td(ctx, proc, tx, ty);
  1721. }
  1722. static void
  1723. pdf_filter_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
  1724. {
  1725. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1726. if (fz_is_empty_rect(p->gstate->clip_rect))
  1727. return;
  1728. pdf_tos_set_matrix(&p->tos, a, b, c, d, e, f);
  1729. p->Tm_pending = 1;
  1730. p->Td_pending = 0;
  1731. p->Tm_adjust = 0;
  1732. }
  1733. static void
  1734. pdf_filter_Tstar(fz_context *ctx, pdf_processor *proc)
  1735. {
  1736. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1737. if (fz_is_empty_rect(p->gstate->clip_rect))
  1738. return;
  1739. p->Tm_adjust = 0;
  1740. filter_flush(ctx, p, FLUSH_ALL);
  1741. pdf_tos_newline(&p->tos, p->gstate->pending.text.leading);
  1742. /* If Tm_pending, then just adjusting the matrix (as
  1743. * pdf_tos_newline has done) is enough. Otherwise we
  1744. * need to actually call the operator. */
  1745. if (!p->Tm_pending && p->chain->op_Tstar)
  1746. p->chain->op_Tstar(ctx, p->chain);
  1747. }
  1748. /* text showing */
  1749. static void
  1750. pdf_filter_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array)
  1751. {
  1752. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1753. if (fz_is_empty_rect(p->gstate->clip_rect))
  1754. return;
  1755. filter_show_text(ctx, p, array);
  1756. }
  1757. static void
  1758. pdf_filter_Tj(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
  1759. {
  1760. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1761. if (fz_is_empty_rect(p->gstate->clip_rect))
  1762. return;
  1763. filter_show_string(ctx, p, (unsigned char *)str, len);
  1764. }
  1765. static void
  1766. pdf_filter_squote(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
  1767. {
  1768. /* Note, we convert all T' operators to (maybe) a T* and a Tj */
  1769. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1770. if (fz_is_empty_rect(p->gstate->clip_rect))
  1771. return;
  1772. /* need to flush text state and clear adjustment before we emit a newline */
  1773. p->Tm_adjust = 0;
  1774. filter_flush(ctx, p, FLUSH_ALL);
  1775. pdf_tos_newline(&p->tos, p->gstate->pending.text.leading);
  1776. /* If Tm_pending, then just adjusting the matrix (as
  1777. * pdf_tos_newline has done) is enough. Otherwise we
  1778. * need to do it manually. */
  1779. if (!p->Tm_pending && p->chain->op_Tstar)
  1780. p->chain->op_Tstar(ctx, p->chain);
  1781. filter_show_string(ctx, p, (unsigned char *)str, len);
  1782. }
  1783. static void
  1784. pdf_filter_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, size_t len)
  1785. {
  1786. /* Note, we convert all T" operators to (maybe) a T*,
  1787. * (maybe) Tc, (maybe) Tw and a Tj. */
  1788. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1789. if (fz_is_empty_rect(p->gstate->clip_rect))
  1790. return;
  1791. /* need to flush text state and clear adjustment before we emit a newline */
  1792. p->Tm_adjust = 0;
  1793. filter_flush(ctx, p, FLUSH_ALL);
  1794. p->gstate->pending.text.word_space = aw;
  1795. p->gstate->pending.text.char_space = ac;
  1796. pdf_tos_newline(&p->tos, p->gstate->pending.text.leading);
  1797. /* If Tm_pending, then just adjusting the matrix (as
  1798. * pdf_tos_newline has done) is enough. Otherwise we
  1799. * need to do it manually. */
  1800. if (!p->Tm_pending && p->chain->op_Tstar)
  1801. p->chain->op_Tstar(ctx, p->chain);
  1802. filter_show_string(ctx, p, (unsigned char*)str, len);
  1803. }
  1804. /* type 3 fonts */
  1805. static void
  1806. pdf_filter_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy)
  1807. {
  1808. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1809. if (fz_is_empty_rect(p->gstate->clip_rect))
  1810. return;
  1811. filter_flush(ctx, p, FLUSH_OP);
  1812. if (p->chain->op_d0)
  1813. p->chain->op_d0(ctx, p->chain, wx, wy);
  1814. }
  1815. static void
  1816. pdf_filter_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury)
  1817. {
  1818. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1819. if (fz_is_empty_rect(p->gstate->clip_rect))
  1820. return;
  1821. filter_flush(ctx, p, FLUSH_OP);
  1822. if (p->chain->op_d1)
  1823. p->chain->op_d1(ctx, p->chain, wx, wy, llx, lly, urx, ury);
  1824. }
  1825. /* color */
  1826. static void
  1827. set_default_cs_values(pdf_filter_gstate_sc *sc, const char *name, fz_colorspace *cs)
  1828. {
  1829. int n = cs ? cs->n : 0;
  1830. int i;
  1831. if (strcmp(name, "Separation") == 0 || strcmp(name, "DeviceN") == 0) {
  1832. for (i = 0; i < n; ++i)
  1833. sc->c[i] = 1;
  1834. }
  1835. else if (strcmp(name, "DeviceGray") == 0 ||
  1836. strcmp(name, "DeviceRGB") == 0 ||
  1837. strcmp(name, "CalGray") == 0 ||
  1838. strcmp(name, "CalRGB") == 0 ||
  1839. strcmp(name, "Indexed") == 0)
  1840. {
  1841. for (i = 0; i < n; ++i)
  1842. sc->c[i] = 0;
  1843. }
  1844. else if (strcmp(name, "DeviceCMYK") == 0)
  1845. {
  1846. sc->c[0] = 0;
  1847. sc->c[1] = 0;
  1848. sc->c[2] = 0;
  1849. sc->c[3] = 1;
  1850. }
  1851. else if (strcmp(name, "Lab") == 0 ||
  1852. strcmp(name, "ICCBased") == 0)
  1853. {
  1854. /* Really we should clamp c[i] to the appropriate range. */
  1855. for (i = 0; i < n; ++i)
  1856. sc->c[i] = 0;
  1857. }
  1858. else
  1859. return;
  1860. sc->pat = NULL;
  1861. sc->shd = NULL;
  1862. sc->name[0] = 0;
  1863. sc->n = n;
  1864. }
  1865. static void
  1866. pdf_filter_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
  1867. {
  1868. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1869. filter_gstate *gstate = p->gstate;
  1870. if (fz_is_empty_rect(p->gstate->clip_rect))
  1871. return;
  1872. fz_strlcpy(gstate->pending.CS.name, name, sizeof gstate->pending.CS.name);
  1873. gstate->pending.CS.cs = cs;
  1874. copy_resource(ctx, p, PDF_NAME(ColorSpace), name);
  1875. set_default_cs_values(&gstate->pending.SC, name, cs);
  1876. }
  1877. static void
  1878. pdf_filter_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
  1879. {
  1880. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1881. filter_gstate *gstate = p->gstate;
  1882. if (fz_is_empty_rect(p->gstate->clip_rect))
  1883. return;
  1884. fz_strlcpy(gstate->pending.cs.name, name, sizeof gstate->pending.cs.name);
  1885. gstate->pending.cs.cs = cs;
  1886. copy_resource(ctx, p, PDF_NAME(ColorSpace), name);
  1887. set_default_cs_values(&gstate->pending.sc, name, cs);
  1888. }
  1889. static void
  1890. pdf_filter_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
  1891. {
  1892. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1893. filter_gstate *gstate = p->gstate;
  1894. int i;
  1895. if (fz_is_empty_rect(p->gstate->clip_rect))
  1896. return;
  1897. fz_strlcpy(gstate->pending.SC.name, name, sizeof gstate->pending.SC.name);
  1898. gstate->pending.SC.pat = pat;
  1899. gstate->pending.SC.shd = NULL;
  1900. gstate->pending.SC.n = n;
  1901. for (i = 0; i < n; ++i)
  1902. gstate->pending.SC.c[i] = color[i];
  1903. copy_resource(ctx, p, PDF_NAME(Pattern), name);
  1904. }
  1905. static void
  1906. pdf_filter_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
  1907. {
  1908. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1909. filter_gstate *gstate = p->gstate;
  1910. int i;
  1911. if (fz_is_empty_rect(p->gstate->clip_rect))
  1912. return;
  1913. fz_strlcpy(gstate->pending.sc.name, name, sizeof gstate->pending.sc.name);
  1914. gstate->pending.sc.pat = pat;
  1915. gstate->pending.sc.shd = NULL;
  1916. gstate->pending.sc.n = n;
  1917. for (i = 0; i < n; ++i)
  1918. gstate->pending.sc.c[i] = color[i];
  1919. copy_resource(ctx, p, PDF_NAME(Pattern), name);
  1920. }
  1921. static void
  1922. pdf_filter_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
  1923. {
  1924. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1925. filter_gstate *gstate = p->gstate;
  1926. if (fz_is_empty_rect(p->gstate->clip_rect))
  1927. return;
  1928. fz_strlcpy(gstate->pending.SC.name, name, sizeof gstate->pending.SC.name);
  1929. gstate->pending.SC.pat = NULL;
  1930. gstate->pending.SC.shd = shade;
  1931. gstate->pending.SC.n = 0;
  1932. copy_resource(ctx, p, PDF_NAME(Pattern), name);
  1933. }
  1934. static void
  1935. pdf_filter_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
  1936. {
  1937. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1938. filter_gstate *gstate = p->gstate;
  1939. if (fz_is_empty_rect(p->gstate->clip_rect))
  1940. return;
  1941. fz_strlcpy(gstate->pending.sc.name, name, sizeof gstate->pending.sc.name);
  1942. gstate->pending.sc.pat = NULL;
  1943. gstate->pending.sc.shd = shade;
  1944. gstate->pending.sc.n = 0;
  1945. copy_resource(ctx, p, PDF_NAME(Pattern), name);
  1946. }
  1947. static void
  1948. pdf_filter_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
  1949. {
  1950. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1951. filter_gstate *gstate = p->gstate;
  1952. int i;
  1953. if (fz_is_empty_rect(p->gstate->clip_rect))
  1954. return;
  1955. gstate->pending.SC.name[0] = 0;
  1956. gstate->pending.SC.pat = NULL;
  1957. gstate->pending.SC.shd = NULL;
  1958. gstate->pending.SC.n = n;
  1959. for (i = 0; i < n; ++i)
  1960. gstate->pending.SC.c[i] = color[i];
  1961. }
  1962. static void
  1963. pdf_filter_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
  1964. {
  1965. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1966. filter_gstate *gstate = p->gstate;
  1967. int i;
  1968. if (fz_is_empty_rect(p->gstate->clip_rect))
  1969. return;
  1970. gstate->pending.sc.name[0] = 0;
  1971. gstate->pending.sc.pat = NULL;
  1972. gstate->pending.sc.shd = NULL;
  1973. gstate->pending.sc.n = n;
  1974. for (i = 0; i < n; ++i)
  1975. gstate->pending.sc.c[i] = color[i];
  1976. }
  1977. static void
  1978. pdf_filter_G(fz_context *ctx, pdf_processor *proc, float g)
  1979. {
  1980. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1981. float color[1] = { g };
  1982. if (fz_is_empty_rect(p->gstate->clip_rect))
  1983. return;
  1984. pdf_filter_CS(ctx, proc, "DeviceGray", fz_device_gray(ctx));
  1985. pdf_filter_SC_color(ctx, proc, 1, color);
  1986. }
  1987. static void
  1988. pdf_filter_g(fz_context *ctx, pdf_processor *proc, float g)
  1989. {
  1990. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  1991. float color[1] = { g };
  1992. if (fz_is_empty_rect(p->gstate->clip_rect))
  1993. return;
  1994. pdf_filter_cs(ctx, proc, "DeviceGray", fz_device_gray(ctx));
  1995. pdf_filter_sc_color(ctx, proc, 1, color);
  1996. }
  1997. static void
  1998. pdf_filter_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
  1999. {
  2000. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2001. float color[3] = { r, g, b };
  2002. if (fz_is_empty_rect(p->gstate->clip_rect))
  2003. return;
  2004. pdf_filter_CS(ctx, proc, "DeviceRGB", fz_device_rgb(ctx));
  2005. pdf_filter_SC_color(ctx, proc, 3, color);
  2006. }
  2007. static void
  2008. pdf_filter_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
  2009. {
  2010. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2011. float color[3] = { r, g, b };
  2012. if (fz_is_empty_rect(p->gstate->clip_rect))
  2013. return;
  2014. pdf_filter_cs(ctx, proc, "DeviceRGB", fz_device_rgb(ctx));
  2015. pdf_filter_sc_color(ctx, proc, 3, color);
  2016. }
  2017. static void
  2018. pdf_filter_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
  2019. {
  2020. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2021. float color[4] = { c, m, y, k };
  2022. if (fz_is_empty_rect(p->gstate->clip_rect))
  2023. return;
  2024. pdf_filter_CS(ctx, proc, "DeviceCMYK", fz_device_cmyk(ctx));
  2025. pdf_filter_SC_color(ctx, proc, 4, color);
  2026. }
  2027. static void
  2028. pdf_filter_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
  2029. {
  2030. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2031. float color[4] = { c, m, y, k };
  2032. if (fz_is_empty_rect(p->gstate->clip_rect))
  2033. return;
  2034. pdf_filter_cs(ctx, proc, "DeviceCMYK", fz_device_cmyk(ctx));
  2035. pdf_filter_sc_color(ctx, proc, 4, color);
  2036. }
  2037. /* shadings, images, xobjects */
  2038. static void
  2039. pdf_filter_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace)
  2040. {
  2041. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2042. if (fz_is_empty_rect(p->gstate->clip_rect))
  2043. return;
  2044. if (p->options->culler)
  2045. {
  2046. fz_matrix ctm = fz_concat(p->gstate->pending.ctm, p->gstate->sent.ctm);
  2047. fz_rect r = { 0, 0, 1, 1 };
  2048. ctm = fz_concat(ctm, p->transform);
  2049. r = fz_transform_rect(r, ctm);
  2050. if (p->options->culler(ctx, p->options->opaque, r, FZ_CULL_IMAGE))
  2051. return;
  2052. }
  2053. filter_flush(ctx, p, FLUSH_ALL);
  2054. if (p->chain->op_BI)
  2055. {
  2056. if (p->options->image_filter)
  2057. {
  2058. fz_matrix ctm = fz_concat(p->gstate->sent.ctm, p->transform);
  2059. image = p->options->image_filter(ctx, p->options->opaque, ctm, "<inline>", image, p->gstate->clip_rect);
  2060. if (image)
  2061. {
  2062. fz_try(ctx)
  2063. {
  2064. copy_resource(ctx, p, PDF_NAME(ColorSpace), colorspace);
  2065. p->chain->op_BI(ctx, p->chain, image, colorspace);
  2066. }
  2067. fz_always(ctx)
  2068. fz_drop_image(ctx, image);
  2069. fz_catch(ctx)
  2070. fz_rethrow(ctx);
  2071. }
  2072. }
  2073. else
  2074. {
  2075. copy_resource(ctx, p, PDF_NAME(ColorSpace), colorspace);
  2076. p->chain->op_BI(ctx, p->chain, image, colorspace);
  2077. }
  2078. }
  2079. }
  2080. static void
  2081. pdf_filter_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
  2082. {
  2083. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2084. if (fz_is_empty_rect(p->gstate->clip_rect))
  2085. return;
  2086. if (p->options->culler)
  2087. {
  2088. fz_matrix ctm = fz_concat(p->gstate->pending.ctm, p->gstate->sent.ctm);
  2089. fz_rect r = { 0, 0, 1, 1 };
  2090. ctm = fz_concat(ctm, p->transform);
  2091. fz_bound_shade(ctx, shade, ctm);
  2092. r = fz_transform_rect(r, ctm);
  2093. if (p->options->culler(ctx, p->options->opaque, r, FZ_CULL_SHADING))
  2094. return;
  2095. }
  2096. filter_flush(ctx, p, FLUSH_ALL);
  2097. if (p->chain->op_sh)
  2098. p->chain->op_sh(ctx, p->chain, name, shade);
  2099. copy_resource(ctx, p, PDF_NAME(Shading), name);
  2100. }
  2101. static void
  2102. pdf_filter_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image)
  2103. {
  2104. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2105. fz_image *new_image;
  2106. if (fz_is_empty_rect(p->gstate->clip_rect))
  2107. return;
  2108. if (p->options->culler)
  2109. {
  2110. fz_matrix ctm = fz_concat(p->gstate->pending.ctm, p->gstate->sent.ctm);
  2111. fz_rect r = { 0, 0, 1, 1 };
  2112. ctm = fz_concat(ctm, p->transform);
  2113. r = fz_transform_rect(r, ctm);
  2114. if (p->options->culler(ctx, p->options->opaque, r, FZ_CULL_IMAGE))
  2115. return;
  2116. }
  2117. filter_flush(ctx, p, FLUSH_ALL);
  2118. if (p->chain->op_Do_image)
  2119. {
  2120. if (p->options->image_filter)
  2121. {
  2122. fz_matrix ctm = fz_concat(p->gstate->sent.ctm, p->transform);
  2123. new_image = p->options->image_filter(ctx, p->options->opaque, ctm, name, image, p->gstate->clip_rect);
  2124. }
  2125. else
  2126. {
  2127. new_image = image;
  2128. }
  2129. if (new_image == image)
  2130. {
  2131. if (p->global_options->instance_forms)
  2132. {
  2133. /* Make up a unique name when instancing forms so we don't accidentally clash. */
  2134. char buf[40];
  2135. pdf_obj *obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(XObject)), name);
  2136. create_resource_name(ctx, p, PDF_NAME(XObject), "Im", buf, sizeof buf);
  2137. add_resource(ctx, p, PDF_NAME(XObject), buf, obj);
  2138. p->chain->op_Do_image(ctx, p->chain, buf, image);
  2139. }
  2140. else
  2141. {
  2142. copy_resource(ctx, p, PDF_NAME(XObject), name);
  2143. p->chain->op_Do_image(ctx, p->chain, name, image);
  2144. }
  2145. }
  2146. else if (new_image != NULL)
  2147. {
  2148. pdf_obj *obj = NULL;
  2149. fz_var(obj);
  2150. fz_try(ctx)
  2151. {
  2152. char buf[40];
  2153. create_resource_name(ctx, p, PDF_NAME(XObject), "Im", buf, sizeof buf);
  2154. obj = pdf_add_image(ctx, p->doc, new_image);
  2155. add_resource(ctx, p, PDF_NAME(XObject), buf, obj);
  2156. p->chain->op_Do_image(ctx, p->chain, buf, new_image);
  2157. }
  2158. fz_always(ctx)
  2159. {
  2160. pdf_drop_obj(ctx, obj);
  2161. fz_drop_image(ctx, new_image);
  2162. }
  2163. fz_catch(ctx)
  2164. fz_rethrow(ctx);
  2165. }
  2166. }
  2167. }
  2168. static void
  2169. pdf_filter_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj)
  2170. {
  2171. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2172. fz_matrix transform;
  2173. if (fz_is_empty_rect(p->gstate->clip_rect))
  2174. return;
  2175. filter_flush(ctx, p, FLUSH_ALL);
  2176. if (p->global_options->instance_forms)
  2177. {
  2178. /* Copy an instance of the form with a new unique name. */
  2179. pdf_obj *new_xobj;
  2180. char buf[40];
  2181. create_resource_name(ctx, p, PDF_NAME(XObject), "Fm", buf, sizeof buf);
  2182. transform = fz_concat(p->gstate->sent.ctm, p->transform);
  2183. new_xobj = pdf_filter_xobject_instance(ctx, xobj, p->rstack->new_rdb, transform, p->global_options, NULL);
  2184. fz_try(ctx)
  2185. {
  2186. add_resource(ctx, p, PDF_NAME(XObject), buf, new_xobj);
  2187. if (p->chain->op_Do_form)
  2188. p->chain->op_Do_form(ctx, p->chain, buf, new_xobj);
  2189. }
  2190. fz_always(ctx)
  2191. pdf_drop_obj(ctx, new_xobj);
  2192. fz_catch(ctx)
  2193. fz_rethrow(ctx);
  2194. }
  2195. else
  2196. {
  2197. copy_resource(ctx, p, PDF_NAME(XObject), name);
  2198. if (p->chain->op_Do_form)
  2199. p->chain->op_Do_form(ctx, p->chain, name, xobj);
  2200. }
  2201. }
  2202. /* marked content */
  2203. static void
  2204. pdf_filter_MP(fz_context *ctx, pdf_processor *proc, const char *tag)
  2205. {
  2206. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2207. if (fz_is_empty_rect(p->gstate->clip_rect))
  2208. return;
  2209. filter_flush(ctx, p, FLUSH_OP);
  2210. if (p->chain->op_MP)
  2211. p->chain->op_MP(ctx, p->chain, tag);
  2212. }
  2213. static void
  2214. pdf_filter_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
  2215. {
  2216. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2217. if (fz_is_empty_rect(p->gstate->clip_rect))
  2218. return;
  2219. filter_flush(ctx, p, FLUSH_OP);
  2220. if (p->chain->op_DP)
  2221. p->chain->op_DP(ctx, p->chain, tag, raw, cooked);
  2222. }
  2223. static void
  2224. pdf_filter_BMC(fz_context *ctx, pdf_processor *proc, const char *tag)
  2225. {
  2226. /* Create a tag, and push it onto pending_tags. If it gets
  2227. * flushed to the stream, it'll be moved from there onto
  2228. * current_tags. */
  2229. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2230. tag_record *bmc = fz_malloc_struct(ctx, tag_record);
  2231. fz_try(ctx)
  2232. bmc->tag = fz_strdup(ctx, tag);
  2233. fz_catch(ctx)
  2234. {
  2235. fz_free(ctx, bmc);
  2236. fz_rethrow(ctx);
  2237. }
  2238. bmc->prev = p->pending_tags;
  2239. p->pending_tags = bmc;
  2240. }
  2241. static void
  2242. pdf_filter_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
  2243. {
  2244. /* Create a tag, and push it onto pending_tags. If it gets
  2245. * flushed to the stream, it'll be moved from there onto
  2246. * current_tags. */
  2247. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2248. tag_record *bdc = fz_malloc_struct(ctx, tag_record);
  2249. pdf_obj *mcid;
  2250. pdf_obj *str;
  2251. fz_try(ctx)
  2252. {
  2253. bdc->bdc = 1;
  2254. bdc->tag = fz_strdup(ctx, tag);
  2255. bdc->raw = pdf_keep_obj(ctx, raw);
  2256. bdc->cooked = pdf_keep_obj(ctx, raw);
  2257. }
  2258. fz_catch(ctx)
  2259. {
  2260. fz_free(ctx, bdc->tag);
  2261. pdf_drop_obj(ctx, bdc->raw);
  2262. pdf_drop_obj(ctx, bdc->cooked);
  2263. fz_free(ctx, bdc);
  2264. fz_rethrow(ctx);
  2265. }
  2266. bdc->prev = p->pending_tags;
  2267. p->pending_tags = bdc;
  2268. /* Look to see if this has an mcid object */
  2269. mcid = pdf_dict_get(ctx, cooked, PDF_NAME(MCID));
  2270. if (!pdf_is_number(ctx, mcid))
  2271. return;
  2272. bdc->mcid_num = pdf_to_int(ctx, mcid);
  2273. bdc->mcid_obj = pdf_keep_obj(ctx, pdf_lookup_mcid_in_mcids(ctx, bdc->mcid_num, p->structarray));
  2274. str = pdf_dict_get(ctx, bdc->mcid_obj, PDF_NAME(Alt));
  2275. if (str)
  2276. bdc->alt.utf8 = pdf_new_utf8_from_pdf_string_obj(ctx, str);
  2277. str = pdf_dict_get(ctx, bdc->mcid_obj, PDF_NAME(ActualText));
  2278. if (str)
  2279. bdc->actualtext.utf8 = pdf_new_utf8_from_pdf_string_obj(ctx, str);
  2280. }
  2281. /* Bin the topmost (most recent) tag from a tag list. */
  2282. static void
  2283. pop_tag(fz_context *ctx, pdf_sanitize_processor *p, tag_record **tags)
  2284. {
  2285. tag_record *tag = *tags;
  2286. if (tag == NULL)
  2287. return;
  2288. *tags = tag->prev;
  2289. fz_free(ctx, tag->tag);
  2290. if (tag->bdc)
  2291. {
  2292. pdf_drop_obj(ctx, tag->raw);
  2293. pdf_drop_obj(ctx, tag->cooked);
  2294. }
  2295. fz_free(ctx, tag->alt.utf8);
  2296. fz_free(ctx, tag->actualtext.utf8);
  2297. pdf_drop_obj(ctx, tag->mcid_obj);
  2298. fz_free(ctx, tag);
  2299. }
  2300. static void
  2301. pdf_filter_EMC(fz_context *ctx, pdf_processor *proc)
  2302. {
  2303. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2304. /* If we have any pending tags, pop one of those. If not,
  2305. * pop one of the current ones, and pass the EMC on. */
  2306. if (p->pending_tags != NULL)
  2307. pop_tag(ctx, p, &p->pending_tags);
  2308. else if (p->current_tags)
  2309. {
  2310. update_mcid(ctx, p);
  2311. copy_resource(ctx, p, PDF_NAME(Properties), pdf_to_name(ctx, p->current_tags->raw));
  2312. pop_tag(ctx, p, &p->current_tags);
  2313. if (p->chain->op_EMC)
  2314. p->chain->op_EMC(ctx, p->chain);
  2315. }
  2316. }
  2317. /* compatibility */
  2318. static void
  2319. pdf_filter_BX(fz_context *ctx, pdf_processor *proc)
  2320. {
  2321. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2322. filter_flush(ctx, p, FLUSH_OP);
  2323. if (p->chain->op_BX)
  2324. p->chain->op_BX(ctx, p->chain);
  2325. }
  2326. static void
  2327. pdf_filter_EX(fz_context *ctx, pdf_processor *proc)
  2328. {
  2329. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2330. filter_flush(ctx, p, FLUSH_OP);
  2331. if (p->chain->op_EX)
  2332. p->chain->op_EX(ctx, p->chain);
  2333. }
  2334. static void
  2335. pdf_filter_END(fz_context *ctx, pdf_processor *proc)
  2336. {
  2337. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2338. filter_flush(ctx, p, FLUSH_TEXT);
  2339. if (p->chain->op_END)
  2340. p->chain->op_END(ctx, p->chain);
  2341. }
  2342. static void
  2343. pdf_close_sanitize_processor(fz_context *ctx, pdf_processor *proc)
  2344. {
  2345. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2346. while (!filter_pop(ctx, p))
  2347. {
  2348. /* Nothing to do in the loop, all work done above */
  2349. }
  2350. pdf_close_processor(ctx, p->chain);
  2351. }
  2352. static void
  2353. pdf_drop_sanitize_processor(fz_context *ctx, pdf_processor *proc)
  2354. {
  2355. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2356. filter_gstate *gs = p->gstate;
  2357. while (gs)
  2358. {
  2359. filter_gstate *next = gs->next;
  2360. pdf_drop_font(ctx, gs->pending.text.font);
  2361. fz_drop_string(ctx, gs->pending.text.fontname);
  2362. pdf_drop_font(ctx, gs->sent.text.font);
  2363. fz_drop_string(ctx, gs->sent.text.fontname);
  2364. fz_free(ctx, gs);
  2365. gs = next;
  2366. }
  2367. while (p->pending_tags)
  2368. pop_tag(ctx, p, &p->pending_tags);
  2369. while (p->current_tags)
  2370. pop_tag(ctx, p, &p->current_tags);
  2371. pdf_drop_obj(ctx, p->structarray);
  2372. pdf_drop_document(ctx, p->doc);
  2373. fz_drop_path(ctx, p->path);
  2374. while (p->rstack)
  2375. {
  2376. resources_stack *stk = p->rstack;
  2377. p->rstack = stk->next;
  2378. pdf_drop_obj(ctx, stk->new_rdb);
  2379. pdf_drop_obj(ctx, stk->old_rdb);
  2380. fz_free(ctx, stk);
  2381. }
  2382. }
  2383. static void
  2384. pdf_sanitize_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res)
  2385. {
  2386. pdf_sanitize_processor *p = (pdf_sanitize_processor *)proc;
  2387. resources_stack *stk = fz_malloc_struct(ctx, resources_stack);
  2388. stk->next = p->rstack;
  2389. p->rstack = stk;
  2390. fz_try(ctx)
  2391. {
  2392. stk->old_rdb = pdf_keep_obj(ctx, res);
  2393. stk->new_rdb = pdf_new_dict(ctx, p->doc, 1);
  2394. pdf_processor_push_resources(ctx, p->chain, stk->new_rdb);
  2395. }
  2396. fz_catch(ctx)
  2397. {
  2398. pdf_drop_obj(ctx, stk->old_rdb);
  2399. pdf_drop_obj(ctx, stk->new_rdb);
  2400. p->rstack = stk->next;
  2401. fz_free(ctx, stk);
  2402. fz_rethrow(ctx);
  2403. }
  2404. }
  2405. static pdf_obj *
  2406. pdf_sanitize_pop_resources(fz_context *ctx, pdf_processor *proc)
  2407. {
  2408. pdf_sanitize_processor *p = (pdf_sanitize_processor *)proc;
  2409. resources_stack *stk = p->rstack;
  2410. p->rstack = stk->next;
  2411. pdf_drop_obj(ctx, stk->old_rdb);
  2412. pdf_drop_obj(ctx, stk->new_rdb);
  2413. fz_free(ctx, stk);
  2414. return pdf_processor_pop_resources(ctx, p->chain);
  2415. }
  2416. static void
  2417. pdf_reset_sanitize_processor(fz_context *ctx, pdf_processor *proc)
  2418. {
  2419. pdf_sanitize_processor *p = (pdf_sanitize_processor*)proc;
  2420. pdf_reset_processor(ctx, p->chain);
  2421. }
  2422. pdf_processor *
  2423. pdf_new_sanitize_filter(
  2424. fz_context *ctx,
  2425. pdf_document *doc,
  2426. pdf_processor *chain,
  2427. int structparents,
  2428. fz_matrix transform,
  2429. pdf_filter_options *options,
  2430. void *sopts_)
  2431. {
  2432. pdf_sanitize_processor *proc = pdf_new_processor(ctx, sizeof *proc);
  2433. pdf_sanitize_filter_options *sopts = (pdf_sanitize_filter_options *)sopts_;
  2434. proc->super.close_processor = pdf_close_sanitize_processor;
  2435. proc->super.drop_processor = pdf_drop_sanitize_processor;
  2436. proc->super.reset_processor = pdf_reset_sanitize_processor;
  2437. proc->super.push_resources = pdf_sanitize_push_resources;
  2438. proc->super.pop_resources = pdf_sanitize_pop_resources;
  2439. /* general graphics state */
  2440. proc->super.op_w = pdf_filter_w;
  2441. proc->super.op_j = pdf_filter_j;
  2442. proc->super.op_J = pdf_filter_J;
  2443. proc->super.op_M = pdf_filter_M;
  2444. proc->super.op_d = pdf_filter_d;
  2445. proc->super.op_ri = pdf_filter_ri;
  2446. proc->super.op_i = pdf_filter_i;
  2447. proc->super.op_gs_begin = pdf_filter_gs_begin;
  2448. proc->super.op_gs_end = pdf_filter_gs_end;
  2449. /* transparency graphics state */
  2450. proc->super.op_gs_BM = pdf_filter_gs_BM;
  2451. proc->super.op_gs_CA = pdf_filter_gs_CA;
  2452. proc->super.op_gs_ca = pdf_filter_gs_ca;
  2453. proc->super.op_gs_SMask = pdf_filter_gs_SMask;
  2454. /* special graphics state */
  2455. proc->super.op_q = pdf_filter_q;
  2456. proc->super.op_Q = pdf_filter_Q;
  2457. proc->super.op_cm = pdf_filter_cm;
  2458. /* path construction */
  2459. proc->super.op_m = pdf_filter_m;
  2460. proc->super.op_l = pdf_filter_l;
  2461. proc->super.op_c = pdf_filter_c;
  2462. proc->super.op_v = pdf_filter_v;
  2463. proc->super.op_y = pdf_filter_y;
  2464. proc->super.op_h = pdf_filter_h;
  2465. proc->super.op_re = pdf_filter_re;
  2466. /* path painting */
  2467. proc->super.op_S = pdf_filter_S;
  2468. proc->super.op_s = pdf_filter_s;
  2469. proc->super.op_F = pdf_filter_F;
  2470. proc->super.op_f = pdf_filter_f;
  2471. proc->super.op_fstar = pdf_filter_fstar;
  2472. proc->super.op_B = pdf_filter_B;
  2473. proc->super.op_Bstar = pdf_filter_Bstar;
  2474. proc->super.op_b = pdf_filter_b;
  2475. proc->super.op_bstar = pdf_filter_bstar;
  2476. proc->super.op_n = pdf_filter_n;
  2477. /* clipping paths */
  2478. proc->super.op_W = pdf_filter_W;
  2479. proc->super.op_Wstar = pdf_filter_Wstar;
  2480. /* text objects */
  2481. proc->super.op_BT = pdf_filter_BT;
  2482. proc->super.op_ET = pdf_filter_ET;
  2483. /* text state */
  2484. proc->super.op_Tc = pdf_filter_Tc;
  2485. proc->super.op_Tw = pdf_filter_Tw;
  2486. proc->super.op_Tz = pdf_filter_Tz;
  2487. proc->super.op_TL = pdf_filter_TL;
  2488. proc->super.op_Tf = pdf_filter_Tf;
  2489. proc->super.op_Tr = pdf_filter_Tr;
  2490. proc->super.op_Ts = pdf_filter_Ts;
  2491. /* text positioning */
  2492. proc->super.op_Td = pdf_filter_Td;
  2493. proc->super.op_TD = pdf_filter_TD;
  2494. proc->super.op_Tm = pdf_filter_Tm;
  2495. proc->super.op_Tstar = pdf_filter_Tstar;
  2496. /* text showing */
  2497. proc->super.op_TJ = pdf_filter_TJ;
  2498. proc->super.op_Tj = pdf_filter_Tj;
  2499. proc->super.op_squote = pdf_filter_squote;
  2500. proc->super.op_dquote = pdf_filter_dquote;
  2501. /* type 3 fonts */
  2502. proc->super.op_d0 = pdf_filter_d0;
  2503. proc->super.op_d1 = pdf_filter_d1;
  2504. /* color */
  2505. proc->super.op_CS = pdf_filter_CS;
  2506. proc->super.op_cs = pdf_filter_cs;
  2507. proc->super.op_SC_color = pdf_filter_SC_color;
  2508. proc->super.op_sc_color = pdf_filter_sc_color;
  2509. proc->super.op_SC_pattern = pdf_filter_SC_pattern;
  2510. proc->super.op_sc_pattern = pdf_filter_sc_pattern;
  2511. proc->super.op_SC_shade = pdf_filter_SC_shade;
  2512. proc->super.op_sc_shade = pdf_filter_sc_shade;
  2513. proc->super.op_G = pdf_filter_G;
  2514. proc->super.op_g = pdf_filter_g;
  2515. proc->super.op_RG = pdf_filter_RG;
  2516. proc->super.op_rg = pdf_filter_rg;
  2517. proc->super.op_K = pdf_filter_K;
  2518. proc->super.op_k = pdf_filter_k;
  2519. /* shadings, images, xobjects */
  2520. proc->super.op_BI = pdf_filter_BI;
  2521. proc->super.op_sh = pdf_filter_sh;
  2522. proc->super.op_Do_image = pdf_filter_Do_image;
  2523. proc->super.op_Do_form = pdf_filter_Do_form;
  2524. /* marked content */
  2525. proc->super.op_MP = pdf_filter_MP;
  2526. proc->super.op_DP = pdf_filter_DP;
  2527. proc->super.op_BMC = pdf_filter_BMC;
  2528. proc->super.op_BDC = pdf_filter_BDC;
  2529. proc->super.op_EMC = pdf_filter_EMC;
  2530. /* compatibility */
  2531. proc->super.op_BX = pdf_filter_BX;
  2532. proc->super.op_EX = pdf_filter_EX;
  2533. /* extgstate */
  2534. proc->super.op_gs_OP = pdf_filter_gs_OP;
  2535. proc->super.op_gs_op = pdf_filter_gs_op;
  2536. proc->super.op_gs_OPM = pdf_filter_gs_OPM;
  2537. proc->super.op_gs_UseBlackPtComp = pdf_filter_gs_UseBlackPtComp;
  2538. proc->super.op_END = pdf_filter_END;
  2539. proc->doc = pdf_keep_document(ctx, doc);
  2540. proc->structparents = structparents;
  2541. if (structparents != -1)
  2542. proc->structarray = pdf_keep_obj(ctx, pdf_lookup_number(ctx, pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/StructTreeRoot/ParentTree"), structparents));
  2543. proc->chain = chain;
  2544. proc->global_options = options;
  2545. proc->options = sopts;
  2546. proc->transform = transform;
  2547. proc->path = NULL;
  2548. fz_try(ctx)
  2549. {
  2550. proc->path = fz_new_path(ctx);
  2551. proc->gstate = fz_malloc_struct(ctx, filter_gstate);
  2552. proc->gstate->pending.ctm = fz_identity;
  2553. proc->gstate->sent.ctm = fz_identity;
  2554. proc->gstate->pending.text.scale = 1;
  2555. proc->gstate->pending.text.size = -1;
  2556. proc->gstate->pending.stroke.linewidth = 1;
  2557. proc->gstate->pending.stroke.miterlimit = 10;
  2558. proc->gstate->sent.text.scale = 1;
  2559. proc->gstate->sent.text.size = -1;
  2560. proc->gstate->sent.stroke.linewidth = 1;
  2561. proc->gstate->sent.stroke.miterlimit = 10;
  2562. proc->gstate->clip_rect = fz_infinite_rect;
  2563. proc->gstate->clip_op = NO_CLIP_OP;
  2564. }
  2565. fz_catch(ctx)
  2566. {
  2567. pdf_drop_processor(ctx, (pdf_processor *) proc);
  2568. fz_rethrow(ctx);
  2569. }
  2570. proc->super.requirements = proc->chain->requirements;
  2571. return (pdf_processor*)proc;
  2572. }