| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383 |
- // Copyright (C) 2004-2025 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include "mupdf/pdf.h"
- #include <string.h>
- #include <math.h>
- #include "mupdf/ucdn.h"
- #define TILE
- /* Enable this to watch changes in the structure stack. */
- #undef DEBUG_STRUCTURE
- /*
- * Emit graphics calls to device.
- */
- typedef struct pdf_run_processor pdf_run_processor;
- static void pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_obj *xobj, pdf_obj *page_resources, fz_matrix transform, int is_smask);
- enum
- {
- PDF_FILL,
- PDF_STROKE,
- };
- enum
- {
- PDF_MAT_NONE,
- PDF_MAT_COLOR,
- PDF_MAT_PATTERN,
- PDF_MAT_SHADE,
- };
- typedef struct
- {
- int kind;
- fz_colorspace *colorspace;
- pdf_pattern *pattern;
- fz_shade *shade;
- int gstate_num;
- fz_color_params color_params;
- float alpha;
- float v[FZ_MAX_COLORS];
- } pdf_material;
- struct pdf_gstate
- {
- fz_matrix ctm;
- int clip_depth;
- /* path stroking */
- fz_stroke_state *stroke_state;
- /* materials */
- pdf_material stroke;
- pdf_material fill;
- /* pattern paint type 2 */
- int ismask;
- /* text state */
- pdf_text_state text;
- /* transparency */
- int blendmode;
- pdf_obj *softmask;
- pdf_obj *softmask_resources;
- pdf_obj *softmask_tr;
- fz_matrix softmask_ctm;
- fz_colorspace *softmask_cs;
- float softmask_bc[FZ_MAX_COLORS];
- int luminosity;
- };
- typedef struct resources_stack
- {
- struct resources_stack *next;
- pdf_obj *resources;
- } resources_stack;
- typedef struct marked_content_stack
- {
- struct marked_content_stack *next;
- pdf_obj *tag;
- pdf_obj *val;
- int structure_pushed;
- } marked_content_stack;
- typedef struct begin_layer_stack
- {
- struct begin_layer_stack *next;
- char *layer;
- } begin_layer_stack;
- struct pdf_run_processor
- {
- pdf_processor super;
- pdf_document *doc;
- fz_device *dev;
- fz_cookie *cookie;
- fz_default_colorspaces *default_cs;
- resources_stack *rstack;
- /* path object state */
- fz_path *path;
- int clip;
- int clip_even_odd;
- /* text object state */
- pdf_text_object_state tos;
- int bidi;
- /* graphics state */
- pdf_gstate *gstate;
- int gcap;
- int gtop;
- int gbot;
- int gparent;
- /* xobject cycle detector */
- pdf_cycle_list *cycle;
- pdf_obj *role_map;
- marked_content_stack *marked_content;
- pdf_obj *mcid_sent;
- pdf_obj *pending_mcid_pop;
- int struct_parent;
- int broken_struct_tree;
- /* Pending begin layers */
- begin_layer_stack *begin_layer;
- begin_layer_stack **next_begin_layer;
- int mc_depth;
- /* The nest_mark array holds a record of the way in which clips and
- * marked content are nested to ensure we pop stuff in the same order
- * that we push it - i.e. to keep calls nested nicely. An entry x,
- * where x >= 0 represents that a push has happened for mc_depth == x.
- * An entry x, where x < 0 means that -x clips have happened at this
- * position. */
- int nest_depth;
- int nest_mark[1024];
- };
- /* Forward definition */
- static void
- pop_any_pending_mcid_changes(fz_context *ctx, pdf_run_processor *pr);
- static void
- push_begin_layer(fz_context *ctx, pdf_run_processor *proc, const char *str)
- {
- begin_layer_stack *s = fz_malloc_struct(ctx, begin_layer_stack);
- fz_try(ctx)
- s->layer = fz_strdup(ctx, str);
- fz_catch(ctx)
- {
- fz_free(ctx, s);
- fz_rethrow(ctx);
- }
- s->next = NULL;
- *proc->next_begin_layer = s;
- proc->next_begin_layer = &s->next;
- }
- static void
- flush_begin_layer(fz_context *ctx, pdf_run_processor *proc)
- {
- begin_layer_stack *s;
- while (proc->begin_layer)
- {
- s = proc->begin_layer;
- if (proc->nest_depth == nelem(proc->nest_mark))
- fz_throw(ctx, FZ_ERROR_LIMIT, "layer/clip nesting too deep");
- proc->nest_mark[proc->nest_depth++] = ++proc->mc_depth;
- fz_begin_layer(ctx, proc->dev, s->layer);
- proc->begin_layer = s->next;
- fz_free(ctx, s->layer);
- fz_free(ctx, s);
- }
- proc->next_begin_layer = &proc->begin_layer;
- }
- static void nest_layer_clip(fz_context *ctx, pdf_run_processor *proc)
- {
- if (proc->nest_depth == nelem(proc->nest_mark))
- fz_throw(ctx, FZ_ERROR_LIMIT, "layer/clip nesting too deep");
- if (proc->nest_depth > 0 && proc->nest_mark[proc->nest_depth-1] < 0)
- {
- /* The last mark was a clip. Just increase that count. */
- proc->nest_mark[proc->nest_depth-1]--;
- }
- else
- {
- /* Create a new entry for a single clip. */
- proc->nest_mark[proc->nest_depth++] = -1;
- }
- }
- static void
- do_end_layer(fz_context *ctx, pdf_run_processor *proc)
- {
- if (proc->nest_depth > 0 && proc->nest_mark[proc->nest_depth-1] == proc->mc_depth)
- {
- fz_end_layer(ctx, proc->dev);
- proc->nest_depth--;
- }
- else
- {
- /* If EMC is unbalanced with q/Q, we will emit the end layer
- * device call before or after the Q operator instead of its true location
- */
- fz_warn(ctx, "invalid marked content and clip nesting");
- }
- if (proc->mc_depth > 0)
- proc->mc_depth--;
- }
- typedef struct
- {
- pdf_obj *softmask;
- fz_colorspace *softmask_cs;
- pdf_obj *page_resources;
- fz_matrix ctm;
- } softmask_save;
- static fz_function *
- load_transfer_function(fz_context *ctx, pdf_obj *obj)
- {
- if (obj == NULL || pdf_name_eq(ctx, obj, PDF_NAME(Identity)))
- return NULL;
- return (fz_function *)pdf_load_function(ctx, obj, 1, 1);
- }
- static pdf_gstate *
- begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save, fz_rect bbox)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_obj *softmask = gstate->softmask;
- fz_colorspace *softmask_cs = gstate->softmask_cs;
- fz_rect mask_bbox;
- fz_matrix tos_save[2], save_ctm;
- fz_matrix mask_matrix;
- fz_colorspace *mask_colorspace;
- int saved_blendmode;
- fz_function *tr = NULL;
- fz_var(tr);
- save->softmask = softmask;
- if (softmask == NULL)
- return gstate;
- save->softmask_cs = softmask_cs;
- save->page_resources = gstate->softmask_resources;
- save->ctm = gstate->softmask_ctm;
- save_ctm = gstate->ctm;
- mask_bbox = pdf_xobject_bbox(ctx, softmask);
- mask_matrix = pdf_xobject_matrix(ctx, softmask);
- pdf_tos_save(ctx, &pr->tos, tos_save);
- mask_colorspace = gstate->softmask_cs;
- if (gstate->luminosity && !mask_colorspace)
- mask_colorspace = fz_device_gray(ctx);
- if (gstate->luminosity)
- mask_bbox = fz_infinite_rect;
- else
- {
- mask_bbox = fz_transform_rect(mask_bbox, mask_matrix);
- mask_bbox = fz_transform_rect(mask_bbox, gstate->softmask_ctm);
- }
- mask_bbox = fz_intersect_rect(mask_bbox, bbox);
- gstate->softmask = NULL;
- gstate->softmask_cs = NULL;
- gstate->softmask_resources = NULL;
- gstate->ctm = gstate->softmask_ctm;
- saved_blendmode = gstate->blendmode;
- fz_try(ctx)
- {
- if (gstate->softmask_tr)
- {
- tr = load_transfer_function(ctx, gstate->softmask_tr);
- pdf_drop_obj(ctx, gstate->softmask_tr);
- gstate->softmask_tr = NULL;
- }
- fz_begin_mask(ctx, pr->dev, mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc, gstate->fill.color_params);
- gstate->blendmode = 0;
- pdf_run_xobject(ctx, pr, softmask, save->page_resources, fz_identity, 1);
- gstate = pr->gstate + pr->gtop;
- gstate->blendmode = saved_blendmode;
- fz_end_mask_tr(ctx, pr->dev, tr);
- }
- fz_always(ctx)
- {
- fz_drop_function(ctx, tr);
- }
- fz_catch(ctx)
- fz_rethrow(ctx);
- pdf_tos_restore(ctx, &pr->tos, tos_save);
- gstate = pr->gstate + pr->gtop;
- gstate->ctm = save_ctm;
- return gstate;
- }
- static void
- end_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- if (save->softmask == NULL)
- return;
- gstate->softmask = save->softmask;
- gstate->softmask_cs = save->softmask_cs;
- gstate->softmask_resources = save->page_resources;
- gstate->softmask_ctm = save->ctm;
- save->softmask = NULL;
- save->page_resources = NULL;
- fz_pop_clip(ctx, pr->dev);
- }
- static pdf_gstate *
- pdf_begin_group(fz_context *ctx, pdf_run_processor *pr, fz_rect bbox, softmask_save *softmask)
- {
- pdf_gstate *gstate = begin_softmask(ctx, pr, softmask, bbox);
- if (gstate->blendmode)
- fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1);
- return pr->gstate + pr->gtop;
- }
- static void
- pdf_end_group(fz_context *ctx, pdf_run_processor *pr, softmask_save *softmask)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- if (gstate->blendmode)
- fz_end_group(ctx, pr->dev);
- end_softmask(ctx, pr, softmask);
- }
- static void
- pdf_show_shade(fz_context *ctx, pdf_run_processor *pr, fz_shade *shd)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- fz_rect bbox;
- softmask_save softmask = { NULL };
- if (pr->super.hidden)
- return;
- bbox = fz_bound_shade(ctx, shd, gstate->ctm);
- fz_try(ctx)
- {
- gstate = pdf_begin_group(ctx, pr, bbox, &softmask);
- /* FIXME: The gstate->ctm in the next line may be wrong; maybe
- * it should be the parent gstates ctm? */
- fz_fill_shade(ctx, pr->dev, shd, gstate->ctm, gstate->fill.alpha, gstate->fill.color_params);
- pdf_end_group(ctx, pr, &softmask);
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, softmask.softmask);
- fz_drop_colorspace(ctx, softmask.softmask_cs);
- pdf_drop_obj(ctx, softmask.page_resources);
- fz_rethrow(ctx);
- }
- }
- static pdf_material *
- pdf_keep_material(fz_context *ctx, pdf_material *mat)
- {
- if (mat->colorspace)
- fz_keep_colorspace(ctx, mat->colorspace);
- if (mat->pattern)
- pdf_keep_pattern(ctx, mat->pattern);
- if (mat->shade)
- fz_keep_shade(ctx, mat->shade);
- return mat;
- }
- static pdf_material *
- pdf_drop_material(fz_context *ctx, pdf_material *mat)
- {
- fz_drop_colorspace(ctx, mat->colorspace);
- pdf_drop_pattern(ctx, mat->pattern);
- fz_drop_shade(ctx, mat->shade);
- return mat;
- }
- static void
- pdf_copy_pattern_gstate(fz_context *ctx, pdf_gstate *dst, const pdf_gstate *src)
- {
- pdf_font_desc *old_font = dst->text.font;
- dst->ctm = src->ctm;
- dst->text = src->text;
- pdf_keep_font(ctx, src->text.font);
- pdf_drop_font(ctx, old_font);
- pdf_drop_obj(ctx, dst->softmask);
- dst->softmask = pdf_keep_obj(ctx, src->softmask);
- pdf_drop_obj(ctx, dst->softmask_resources);
- dst->softmask_resources = pdf_keep_obj(ctx, src->softmask_resources);
- fz_drop_colorspace(ctx, dst->softmask_cs);
- dst->softmask_cs = fz_keep_colorspace(ctx, src->softmask_cs);
- fz_drop_stroke_state(ctx, dst->stroke_state);
- dst->stroke_state = fz_keep_stroke_state(ctx, src->stroke_state);
- }
- static void
- pdf_unset_pattern(fz_context *ctx, pdf_run_processor *pr, int what)
- {
- pdf_gstate *gs = pr->gstate + pr->gtop;
- pdf_material *mat;
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
- if (mat->kind == PDF_MAT_PATTERN)
- {
- pdf_drop_pattern(ctx, mat->pattern);
- mat->pattern = NULL;
- mat->kind = PDF_MAT_COLOR;
- }
- }
- static void
- pdf_keep_gstate(fz_context *ctx, pdf_gstate *gs)
- {
- pdf_keep_material(ctx, &gs->stroke);
- pdf_keep_material(ctx, &gs->fill);
- if (gs->text.font)
- pdf_keep_font(ctx, gs->text.font);
- if (gs->softmask)
- pdf_keep_obj(ctx, gs->softmask);
- if (gs->softmask_cs)
- fz_keep_colorspace(ctx, gs->softmask_cs);
- if (gs->softmask_resources)
- pdf_keep_obj(ctx, gs->softmask_resources);
- fz_keep_stroke_state(ctx, gs->stroke_state);
- pdf_keep_obj(ctx, gs->softmask_tr);
- }
- static void
- pdf_drop_gstate(fz_context *ctx, pdf_gstate *gs)
- {
- pdf_drop_material(ctx, &gs->stroke);
- pdf_drop_material(ctx, &gs->fill);
- pdf_drop_font(ctx, gs->text.font);
- pdf_drop_obj(ctx, gs->softmask);
- fz_drop_colorspace(ctx, gs->softmask_cs);
- pdf_drop_obj(ctx, gs->softmask_resources);
- fz_drop_stroke_state(ctx, gs->stroke_state);
- pdf_drop_obj(ctx, gs->softmask_tr);
- }
- static void
- pdf_gsave(fz_context *ctx, pdf_run_processor *pr)
- {
- if (pr->gtop == pr->gcap-1)
- {
- if (pr->gcap * 2 >= 4096)
- fz_throw(ctx, FZ_ERROR_LIMIT, "too many nested graphics states");
- pr->gstate = fz_realloc_array(ctx, pr->gstate, pr->gcap*2, pdf_gstate);
- pr->gcap *= 2;
- }
- memcpy(&pr->gstate[pr->gtop + 1], &pr->gstate[pr->gtop], sizeof(pdf_gstate));
- pr->gtop++;
- pdf_keep_gstate(ctx, &pr->gstate[pr->gtop]);
- }
- static void
- pdf_grestore(fz_context *ctx, pdf_run_processor *pr)
- {
- pdf_gstate *gs = pr->gstate + pr->gtop;
- int clip_depth = gs->clip_depth;
- if (pr->gtop <= pr->gbot)
- {
- fz_warn(ctx, "gstate underflow in content stream");
- return;
- }
- pdf_drop_gstate(ctx, gs);
- pr->gtop --;
- gs = pr->gstate + pr->gtop;
- while (clip_depth > gs->clip_depth)
- {
- fz_try(ctx)
- {
- // End layer early (before Q) if unbalanced Q appears between BMC and EMC.
- while (pr->nest_depth > 0 && pr->nest_mark[pr->nest_depth-1] >= 0)
- {
- fz_end_layer(ctx, pr->dev);
- pr->nest_depth--;
- }
- if (pr->nest_depth > 0)
- {
- /* So this one must be a clip record. */
- fz_pop_clip(ctx, pr->dev);
- /* Pop a single clip record off. */
- pr->nest_mark[pr->nest_depth-1]++;
- if (pr->nest_mark[pr->nest_depth-1] == 0)
- pr->nest_depth--;
- }
- // End layer late (after Q) if unbalanced EMC appears between q and Q.
- while (pr->nest_depth > 0 && pr->nest_mark[pr->nest_depth-1] > pr->mc_depth)
- {
- fz_end_layer(ctx, pr->dev);
- pr->nest_depth--;
- }
- }
- fz_catch(ctx)
- {
- /* Silently swallow the problem - restores must
- * never throw! */
- fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); // FIXME - unsure if we can throw here?
- fz_report_error(ctx);
- }
- clip_depth--;
- }
- }
- static pdf_gstate *
- pdf_show_pattern(fz_context *ctx, pdf_run_processor *pr, pdf_pattern *pat, int pat_gstate_num, fz_rect area, int what)
- {
- pdf_gstate *gstate;
- pdf_gstate *pat_gstate;
- int gparent_save;
- fz_matrix ptm, invptm, gparent_save_ctm;
- int x0, y0, x1, y1;
- float fx0, fy0, fx1, fy1;
- fz_rect local_area;
- int oldbot;
- int id;
- pdf_gsave(ctx, pr);
- gstate = pr->gstate + pr->gtop;
- pat_gstate = pr->gstate + pat_gstate_num;
- /* Patterns are run with the gstate of the parent */
- pdf_copy_pattern_gstate(ctx, gstate, pat_gstate);
- if (pat->ismask)
- {
- /* Inhibit any changes to the color since we're drawing an uncolored pattern. */
- gstate->ismask = 1;
- pdf_unset_pattern(ctx, pr, PDF_FILL);
- pdf_unset_pattern(ctx, pr, PDF_STROKE);
- if (what == PDF_FILL)
- {
- pdf_drop_material(ctx, &gstate->stroke);
- pdf_keep_material(ctx, &gstate->fill);
- gstate->stroke = gstate->fill;
- }
- if (what == PDF_STROKE)
- {
- pdf_drop_material(ctx, &gstate->fill);
- pdf_keep_material(ctx, &gstate->stroke);
- gstate->fill = gstate->stroke;
- }
- id = 0; /* don't cache uncolored patterns, since we colorize them when drawing */
- }
- else
- {
- // TODO: unset only the current fill/stroke or both?
- pdf_unset_pattern(ctx, pr, what);
- id = pat->id;
- }
- /* don't apply soft masks to objects in the pattern as well */
- if (gstate->softmask)
- {
- pdf_drop_obj(ctx, gstate->softmask);
- gstate->softmask = NULL;
- }
- ptm = fz_concat(pat->matrix, pat_gstate->ctm);
- invptm = fz_invert_matrix(ptm);
- /* The parent_ctm is amended with our pattern matrix */
- gparent_save = pr->gparent;
- pr->gparent = pr->gtop-1;
- gparent_save_ctm = pr->gstate[pr->gparent].ctm;
- pr->gstate[pr->gparent].ctm = ptm;
- /* patterns are painted using the parent_ctm. area = bbox of
- * shape to be filled in device space. Map it back to pattern
- * space. */
- local_area = fz_transform_rect(area, invptm);
- fx0 = (local_area.x0 - pat->bbox.x0) / pat->xstep;
- fy0 = (local_area.y0 - pat->bbox.y0) / pat->ystep;
- fx1 = (local_area.x1 - pat->bbox.x0) / pat->xstep;
- fy1 = (local_area.y1 - pat->bbox.y0) / pat->ystep;
- if (fx0 > fx1)
- {
- float t = fx0; fx0 = fx1; fx1 = t;
- }
- if (fy0 > fy1)
- {
- float t = fy0; fy0 = fy1; fy1 = t;
- }
- #ifdef TILE
- /* We have tried various formulations in the past, but this one is
- * best we've found; only use it as a tile if a whole repeat is
- * required in at least one direction. Note, that this allows for
- * 'sections' of 4 tiles to be show, but all non-overlapping. */
- if (fx1-fx0 > 1 || fy1-fy0 > 1)
- #else
- if (0)
- #endif
- {
- int cached = fz_begin_tile_id(ctx, pr->dev, local_area, pat->bbox, pat->xstep, pat->ystep, ptm, id);
- if (!cached)
- {
- gstate->ctm = ptm;
- oldbot = pr->gbot;
- pr->gbot = pr->gtop;
- pdf_gsave(ctx, pr);
- pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL, NULL);
- pdf_grestore(ctx, pr);
- while (pr->gtop > pr->gbot)
- pdf_grestore(ctx, pr);
- pr->gbot = oldbot;
- }
- fz_end_tile(ctx, pr->dev);
- }
- else
- {
- int x, y;
- /* When calculating the number of tiles required, we adjust by
- * a small amount to allow for rounding errors. By choosing
- * this amount to be smaller than 1/256, we guarantee we won't
- * cause problems that will be visible even under our most
- * extreme antialiasing. */
- x0 = floorf(fx0 + 0.001f);
- y0 = floorf(fy0 + 0.001f);
- x1 = ceilf(fx1 - 0.001f);
- y1 = ceilf(fy1 - 0.001f);
- /* The above adjustments cause problems for sufficiently
- * large values for xstep/ystep which may be used if the
- * pattern is expected to be rendered exactly once. */
- if (fx1 > fx0 && x1 == x0)
- x1 = x0 + 1;
- if (fy1 > fy0 && y1 == y0)
- y1 = y0 + 1;
- for (y = y0; y < y1; y++)
- {
- for (x = x0; x < x1; x++)
- {
- /* Calls to pdf_process_contents may cause the
- * gstate array to be realloced to be larger.
- * That can invalidate gstate. Hence reload
- * it each time round the loop. */
- gstate = pr->gstate + pr->gtop;
- gstate->ctm = fz_pre_translate(ptm, x * pat->xstep, y * pat->ystep);
- oldbot = pr->gbot;
- pr->gbot = pr->gtop;
- pdf_gsave(ctx, pr);
- pdf_process_contents(ctx, (pdf_processor*)pr, pat->document, pat->resources, pat->contents, NULL, NULL);
- pdf_grestore(ctx, pr);
- while (pr->gtop > pr->gbot)
- pdf_grestore(ctx, pr);
- pr->gbot = oldbot;
- }
- }
- }
- pr->gstate[pr->gparent].ctm = gparent_save_ctm;
- pr->gparent = gparent_save;
- pdf_grestore(ctx, pr);
- return pr->gstate + pr->gtop;
- }
- static void
- pdf_show_image_imp(fz_context *ctx, pdf_run_processor *pr, fz_image *image, fz_matrix image_ctm, fz_rect bbox)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- fz_color_params cp = gstate->fill.color_params;
- if (image->has_intent)
- cp.ri = image->intent;
- if (image->colorspace)
- {
- fz_fill_image(ctx, pr->dev, image, image_ctm, gstate->fill.alpha, cp);
- }
- else if (gstate->fill.kind == PDF_MAT_COLOR)
- {
- fz_fill_image_mask(ctx, pr->dev, image, image_ctm, gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, cp);
- }
- else if (gstate->fill.kind == PDF_MAT_PATTERN && gstate->fill.pattern)
- {
- fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox);
- gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL);
- fz_pop_clip(ctx, pr->dev);
- }
- else if (gstate->fill.kind == PDF_MAT_SHADE && gstate->fill.shade)
- {
- fz_clip_image_mask(ctx, pr->dev, image, image_ctm, bbox);
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, cp);
- fz_pop_clip(ctx, pr->dev);
- }
- }
- static void
- pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- fz_matrix image_ctm;
- fz_rect bbox;
- if (pr->super.hidden)
- return;
- /* image can be NULL here if we are, for example, running to an
- * stext device. */
- if (image == NULL)
- return;
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- /* PDF has images bottom-up, so flip them right side up here */
- image_ctm = fz_pre_scale(fz_pre_translate(gstate->ctm, 0, 1), 1, -1);
- bbox = fz_transform_rect(fz_unit_rect, image_ctm);
- if (image->mask && gstate->blendmode)
- {
- /* apply blend group even though we skip the soft mask */
- fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 0, gstate->blendmode, 1);
- fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox);
- pdf_show_image_imp(ctx, pr, image, image_ctm, bbox);
- fz_pop_clip(ctx, pr->dev);
- fz_end_group(ctx, pr->dev);
- }
- else if (image->mask)
- {
- fz_clip_image_mask(ctx, pr->dev, image->mask, image_ctm, bbox);
- pdf_show_image_imp(ctx, pr, image, image_ctm, bbox);
- fz_pop_clip(ctx, pr->dev);
- }
- else
- {
- softmask_save softmask = { NULL };
- fz_try(ctx)
- {
- gstate = pdf_begin_group(ctx, pr, bbox, &softmask);
- pdf_show_image_imp(ctx, pr, image, image_ctm, bbox);
- pdf_end_group(ctx, pr, &softmask);
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, softmask.softmask);
- fz_drop_colorspace(ctx, softmask.softmask_cs);
- pdf_drop_obj(ctx, softmask.page_resources);
- fz_rethrow(ctx);
- }
- }
- }
- static void
- pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, int dostroke, int even_odd)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- fz_path *path;
- fz_rect bbox;
- softmask_save softmask = { NULL };
- int knockout_group = 0;
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- if (dostroke) {
- if (pr->dev->flags & (FZ_DEVFLAG_STROKECOLOR_UNDEFINED | FZ_DEVFLAG_LINEJOIN_UNDEFINED | FZ_DEVFLAG_LINEWIDTH_UNDEFINED | FZ_DEVFLAG_DASH_PATTERN_UNDEFINED))
- pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- else if (gstate->stroke_state->dash_len != 0 && pr->dev->flags & (FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED))
- pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- else if (gstate->stroke_state->linejoin == FZ_LINEJOIN_MITER && (pr->dev->flags & FZ_DEVFLAG_MITERLIMIT_UNDEFINED))
- pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- }
- if (dofill) {
- if (pr->dev->flags & FZ_DEVFLAG_FILLCOLOR_UNDEFINED)
- pr->dev->flags |= FZ_DEVFLAG_UNCACHEABLE;
- }
- path = pr->path;
- pr->path = fz_new_path(ctx);
- fz_try(ctx)
- {
- if (doclose)
- fz_closepath(ctx, path);
- bbox = fz_bound_path(ctx, path, (dostroke ? gstate->stroke_state : NULL), gstate->ctm);
- if (pr->super.hidden)
- dostroke = dofill = 0;
- if (dofill || dostroke)
- gstate = pdf_begin_group(ctx, pr, bbox, &softmask);
- if (dofill && dostroke)
- {
- /* We may need to push a knockout group */
- if (gstate->stroke.alpha == 0)
- {
- /* No need for group, as stroke won't do anything */
- }
- else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL)
- {
- /* No need for group, as stroke won't show up */
- }
- else
- {
- knockout_group = 1;
- fz_begin_group(ctx, pr->dev, bbox, NULL, 0, 1, FZ_BLEND_NORMAL, 1);
- }
- }
- if (dofill)
- {
- switch (gstate->fill.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_fill_path(ctx, pr->dev, path, even_odd, gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->fill.pattern)
- {
- fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox);
- gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, bbox, PDF_FILL);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->fill.shade)
- {
- fz_clip_path(ctx, pr->dev, path, even_odd, gstate->ctm, bbox);
- /* The cluster and page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm. */
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- }
- }
- if (dostroke)
- {
- switch (gstate->stroke.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->stroke.pattern)
- {
- fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox);
- gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, bbox, PDF_STROKE);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->stroke.shade)
- {
- fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, gstate->ctm, bbox);
- fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- }
- }
- if (knockout_group)
- fz_end_group(ctx, pr->dev);
- if (dofill || dostroke)
- pdf_end_group(ctx, pr, &softmask);
- if (pr->clip)
- {
- nest_layer_clip(ctx, pr);
- gstate->clip_depth++;
- fz_clip_path(ctx, pr->dev, path, pr->clip_even_odd, gstate->ctm, bbox);
- pr->clip = 0;
- }
- }
- fz_always(ctx)
- {
- fz_drop_path(ctx, path);
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, softmask.softmask);
- fz_drop_colorspace(ctx, softmask.softmask_cs);
- pdf_drop_obj(ctx, softmask.page_resources);
- fz_rethrow(ctx);
- }
- }
- /*
- * Assemble and emit text
- */
- static pdf_gstate *
- pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- fz_text *text;
- int dofill;
- int dostroke;
- int doclip;
- int doinvisible;
- softmask_save softmask = { NULL };
- int knockout_group = 0;
- text = pdf_tos_get_text(ctx, &pr->tos);
- if (!text)
- return gstate;
- pop_any_pending_mcid_changes(ctx, pr);
- /* If we are going to output text, we need to have flushed any begin layers first. */
- flush_begin_layer(ctx, pr);
- dofill = dostroke = doclip = doinvisible = 0;
- switch (pr->tos.text_mode)
- {
- case 0: dofill = 1; break;
- case 1: dostroke = 1; break;
- case 2: dofill = dostroke = 1; break;
- case 3: doinvisible = 1; break;
- case 4: dofill = doclip = 1; break;
- case 5: dostroke = doclip = 1; break;
- case 6: dofill = dostroke = doclip = 1; break;
- case 7: doclip = 1; break;
- }
- if (pr->super.hidden)
- dostroke = dofill = 0;
- fz_try(ctx)
- {
- fz_rect tb = fz_transform_rect(pr->tos.text_bbox, gstate->ctm);
- if (dostroke)
- tb = fz_adjust_rect_for_stroke(ctx, tb, gstate->stroke_state, gstate->ctm);
- /* Don't bother sending a text group with nothing in it */
- if (!text->head)
- break;
- if (dofill || dostroke)
- gstate = pdf_begin_group(ctx, pr, tb, &softmask);
- if (dofill && dostroke)
- {
- /* We may need to push a knockout group */
- if (gstate->stroke.alpha == 0)
- {
- /* No need for group, as stroke won't do anything */
- }
- else if (gstate->stroke.alpha == 1.0f && gstate->blendmode == FZ_BLEND_NORMAL)
- {
- /* No need for group, as stroke won't show up */
- }
- else
- {
- knockout_group = 1;
- fz_begin_group(ctx, pr->dev, tb, NULL, 0, 1, FZ_BLEND_NORMAL, 1);
- }
- }
- if (doinvisible)
- fz_ignore_text(ctx, pr->dev, text, gstate->ctm);
- if (dofill)
- {
- switch (gstate->fill.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_fill_text(ctx, pr->dev, text, gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, gstate->fill.color_params);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->fill.pattern)
- {
- fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb);
- gstate = pdf_show_pattern(ctx, pr, gstate->fill.pattern, gstate->fill.gstate_num, tb, PDF_FILL);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->fill.shade)
- {
- fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb);
- /* Page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm */
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, gstate->fill.color_params);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- }
- }
- if (dostroke)
- {
- switch (gstate->stroke.kind)
- {
- case PDF_MAT_NONE:
- break;
- case PDF_MAT_COLOR:
- fz_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, gstate->stroke.color_params);
- break;
- case PDF_MAT_PATTERN:
- if (gstate->stroke.pattern)
- {
- fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb);
- gstate = pdf_show_pattern(ctx, pr, gstate->stroke.pattern, gstate->stroke.gstate_num, tb, PDF_STROKE);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- case PDF_MAT_SHADE:
- if (gstate->stroke.shade)
- {
- fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, gstate->ctm, tb);
- fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, gstate->stroke.color_params);
- fz_pop_clip(ctx, pr->dev);
- }
- break;
- }
- }
- if (knockout_group)
- fz_end_group(ctx, pr->dev);
- if (dofill || dostroke)
- pdf_end_group(ctx, pr, &softmask);
- if (doclip)
- {
- nest_layer_clip(ctx, pr);
- gstate->clip_depth++;
- fz_clip_text(ctx, pr->dev, text, gstate->ctm, tb);
- }
- }
- fz_always(ctx)
- {
- fz_drop_text(ctx, text);
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, softmask.softmask);
- fz_drop_colorspace(ctx, softmask.softmask_cs);
- pdf_drop_obj(ctx, softmask.page_resources);
- fz_rethrow(ctx);
- }
- return pr->gstate + pr->gtop;
- }
- static int
- guess_bidi_level(int bidiclass, int cur_bidi)
- {
- switch (bidiclass)
- {
- /* strong */
- case UCDN_BIDI_CLASS_L: return 0;
- case UCDN_BIDI_CLASS_R: return 1;
- case UCDN_BIDI_CLASS_AL: return 1;
- /* weak */
- case UCDN_BIDI_CLASS_EN:
- case UCDN_BIDI_CLASS_ES:
- case UCDN_BIDI_CLASS_ET:
- return 0;
- case UCDN_BIDI_CLASS_AN:
- return 1;
- case UCDN_BIDI_CLASS_CS:
- case UCDN_BIDI_CLASS_NSM:
- case UCDN_BIDI_CLASS_BN:
- return cur_bidi;
- /* neutral */
- case UCDN_BIDI_CLASS_B:
- case UCDN_BIDI_CLASS_S:
- case UCDN_BIDI_CLASS_WS:
- case UCDN_BIDI_CLASS_ON:
- return cur_bidi;
- /* embedding, override, pop ... we don't support them */
- default:
- return 0;
- }
- }
- static void
- pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid, fz_text_language lang)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_font_desc *fontdesc = gstate->text.font;
- fz_matrix trm;
- float adv;
- int gid;
- int ucsbuf[PDF_MRANGE_CAP];
- int ucslen;
- int i;
- int render_direct;
- int type3_hitr;
- gid = pdf_tos_make_trm(ctx, &pr->tos, &gstate->text, fontdesc, cid, &trm, &adv);
- /* If we are uncachable, then render direct. */
- render_direct = !fz_glyph_cacheable(ctx, fontdesc->font, gid);
- /* PDF spec: ISO 32000-2 latest version at the time of writing:
- * Section 9.3.6:
- * Where text is drawn using a Type 3 font:
- * + if text rendering mode is set to a value of 3 or 7, the text shall not be rendered.
- * + if text rendering mode is set to a value other than 3 or 7, the text shall be rendered using the glyph descriptions in the Type 3 font.
- * + If text rendering mode is set to a value of 4, 5, 6 or 7, nothing shall be added to the clipping path.
- */
- type3_hitr = (fontdesc->font->t3procs && pr->tos.text_mode >= 4);
- /* flush buffered text if rendermode has changed */
- if (!pr->tos.text || gstate->text.render != pr->tos.text_mode || render_direct || type3_hitr)
- {
- gstate = pdf_flush_text(ctx, pr);
- pdf_tos_reset(ctx, &pr->tos, gstate->text.render);
- }
- /* If Type3 and tr >= 4, then ignore the clipping path part. */
- if (type3_hitr)
- pr->tos.text_mode -= 4;
- if (render_direct && pr->tos.text_mode != 3 /* or 7, by type3_hitr */)
- {
- /* Render the glyph stream direct here (only happens for
- * type3 glyphs that seem to inherit current graphics
- * attributes, or type 3 glyphs within type3 glyphs). */
- fz_matrix composed = fz_concat(trm, gstate->ctm);
- /* Whatever problems the underlying char has is no concern of
- * ours. Store the flags, restore them afterwards. */
- int old_flags = pr->dev->flags;
- pdf_gstate *fill_gstate = NULL;
- pdf_gstate *stroke_gstate = NULL;
- pdf_gsave(ctx, pr);
- gstate = pr->gstate + pr->gtop;
- if (gstate->fill.kind == PDF_MAT_PATTERN && gstate->fill.gstate_num >= 0)
- fill_gstate = pr->gstate + gstate->fill.gstate_num;
- if (gstate->stroke.kind == PDF_MAT_PATTERN && gstate->stroke.gstate_num >= 0)
- stroke_gstate = pr->gstate + gstate->stroke.gstate_num;
- pdf_drop_font(ctx, gstate->text.font);
- gstate->text.font = NULL; /* don't inherit the current font... */
- fz_render_t3_glyph_direct(ctx, pr->dev, fontdesc->font, gid, composed, gstate, pr->default_cs, fill_gstate, stroke_gstate);
- pr->dev->flags = old_flags;
- pdf_grestore(ctx, pr);
- /* Render text invisibly so that it can still be extracted. */
- pr->tos.text_mode = 3;
- }
- ucslen = 0;
- if (fontdesc->to_unicode)
- ucslen = pdf_lookup_cmap_full(fontdesc->to_unicode, cid, ucsbuf);
- /* convert ascii whitespace control characters to spaces */
- if (ucslen == 1 && (ucsbuf[0] >= 8 && ucsbuf[0] <= 13))
- ucsbuf[0] = ' ';
- /* ignore obviously bad values in ToUnicode, fall back to the cid_to_ucs table */
- if (ucslen == 1 && (ucsbuf[0] < 32 || (ucsbuf[0] >= 127 && ucsbuf[0] < 160)))
- ucslen = 0;
- if (ucslen == 0 && (size_t)cid < fontdesc->cid_to_ucs_len)
- {
- ucsbuf[0] = fontdesc->cid_to_ucs[cid];
- ucslen = 1;
- }
- if (ucslen == 0 || (ucslen == 1 && ucsbuf[0] == 0))
- {
- ucsbuf[0] = FZ_REPLACEMENT_CHARACTER;
- ucslen = 1;
- }
- /* guess bidi level from unicode value */
- pr->bidi = guess_bidi_level(ucdn_get_bidi_class(ucsbuf[0]), pr->bidi);
- /* add glyph to textobject */
- fz_show_glyph_aux(ctx, pr->tos.text, fontdesc->font, trm, adv, gid, ucsbuf[0], cid, fontdesc->wmode, pr->bidi, FZ_BIDI_NEUTRAL, lang);
- /* add filler glyphs for one-to-many unicode mapping */
- for (i = 1; i < ucslen; i++)
- fz_show_glyph_aux(ctx, pr->tos.text, fontdesc->font, trm, 0, -1, ucsbuf[i], -1, fontdesc->wmode, pr->bidi, FZ_BIDI_NEUTRAL, lang);
- pdf_tos_move_after_char(ctx, &pr->tos);
- }
- static void
- pdf_show_space(fz_context *ctx, pdf_run_processor *pr, float tadj)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_font_desc *fontdesc = gstate->text.font;
- if (fontdesc->wmode == 0)
- pr->tos.tm = fz_pre_translate(pr->tos.tm, tadj * gstate->text.scale, 0);
- else
- pr->tos.tm = fz_pre_translate(pr->tos.tm, 0, tadj);
- }
- static int
- int_in_singleton_or_array(fz_context *ctx, pdf_obj *k, int id)
- {
- /* In the most common case the /K value will be id. */
- if (pdf_is_int(ctx, k) && pdf_to_int(ctx, k) == id)
- return 1;
- /* In the next most common case, there will be an array of
- * items, one of which is k. */
- if (pdf_is_array(ctx, k))
- {
- int i, n = pdf_array_len(ctx, k);
- for (i = 0; i < n; i++)
- {
- pdf_obj *o = pdf_array_get(ctx, k, i);
- if (pdf_is_int(ctx, o) && pdf_to_int(ctx, o) == id)
- return 1;
- }
- }
- return 0;
- }
- pdf_obj *
- pdf_lookup_mcid_in_mcids(fz_context *ctx, int id, pdf_obj *mcids)
- {
- pdf_obj *mcid = pdf_array_get(ctx, mcids, id);
- pdf_obj *k = pdf_dict_get(ctx, mcid, PDF_NAME(K));
- int i, n;
- if (int_in_singleton_or_array(ctx, k, id))
- return mcid;
- /* At this point, something has gone wrong. One common case that
- * appears to fail is where the MCIDs array has the right things
- * in, but at the wrong indexes. So do some searching. */
- n = pdf_array_len(ctx, mcids);
- for (i = 0; i < n; i++)
- {
- pdf_obj *o = pdf_array_get(ctx, mcids, i);
- if (int_in_singleton_or_array(ctx, pdf_dict_get(ctx, o, PDF_NAME(K)), id))
- return o;
- }
- return NULL;
- }
- static pdf_obj *
- lookup_mcid(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val)
- {
- pdf_obj *mcid;
- int id;
- pdf_obj *mcids;
- if (proc->struct_parent == -1)
- return NULL;
- mcid = pdf_dict_get(ctx, val, PDF_NAME(MCID));
- if (!mcid)
- return NULL;
- if (!pdf_is_number(ctx, mcid))
- return NULL;
- id = pdf_to_int(ctx, mcid);
- mcids = pdf_lookup_number(ctx, pdf_dict_getl(ctx, pdf_trailer(ctx, proc->doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), PDF_NAME(ParentTree), NULL), proc->struct_parent);
- return pdf_lookup_mcid_in_mcids(ctx, id, mcids);
- }
- static fz_text_language
- find_lang_from_mc(fz_context *ctx, pdf_run_processor *pr)
- {
- marked_content_stack *mc;
- for (mc = pr->marked_content; mc != NULL; mc = mc->next)
- {
- size_t len;
- const char *lang;
- lang = pdf_dict_get_string(ctx, mc->val, PDF_NAME(Lang), &len);
- if (!lang)
- lang = pdf_dict_get_string(ctx, lookup_mcid(ctx, pr, mc->val), PDF_NAME(Lang), &len);
- if (lang)
- {
- char text[8];
- memcpy(text, lang, len < 8 ? len : 7);
- text[len < 8 ? len : 7] = 0;
- return fz_text_language_from_string(text);
- }
- }
- return FZ_LANG_UNSET;
- }
- static void
- show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, size_t len)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_font_desc *fontdesc = gstate->text.font;
- unsigned char *end = buf + len;
- unsigned int cpt;
- int cid;
- fz_text_language lang = find_lang_from_mc(ctx, pr);
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- while (buf < end)
- {
- int w = pdf_decode_cmap(fontdesc->encoding, buf, end, &cpt);
- buf += w;
- cid = pdf_lookup_cmap(fontdesc->encoding, cpt);
- if (cid >= 0)
- pdf_show_char(ctx, pr, cid, lang);
- else
- fz_warn(ctx, "cannot encode character");
- if (cpt == 32 && w == 1)
- {
- /* Bug 703151: pdf_show_char can realloc gstate. */
- gstate = pr->gstate + pr->gtop;
- pdf_show_space(ctx, pr, gstate->text.word_space);
- }
- }
- }
- static void
- pdf_show_string(fz_context *ctx, pdf_run_processor *pr, unsigned char *buf, size_t len)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_font_desc *fontdesc = gstate->text.font;
- if (!fontdesc)
- {
- fz_warn(ctx, "cannot draw text since font and size not set");
- return;
- }
- show_string(ctx, pr, buf, len);
- }
- static void
- pdf_show_text(fz_context *ctx, pdf_run_processor *pr, pdf_obj *text)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_font_desc *fontdesc = gstate->text.font;
- int i;
- if (!fontdesc)
- {
- fz_warn(ctx, "cannot draw text since font and size not set");
- return;
- }
- if (pdf_is_array(ctx, text))
- {
- int n = pdf_array_len(ctx, text);
- for (i = 0; i < n; i++)
- {
- pdf_obj *item = pdf_array_get(ctx, text, i);
- if (pdf_is_string(ctx, item))
- show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, item), pdf_to_str_len(ctx, item));
- else
- pdf_show_space(ctx, pr, - pdf_to_real(ctx, item) * gstate->text.size * 0.001f);
- }
- }
- else if (pdf_is_string(ctx, text))
- {
- pdf_show_string(ctx, pr, (unsigned char *)pdf_to_str_buf(ctx, text), pdf_to_str_len(ctx, text));
- }
- }
- /*
- * Interpreter and graphics state stack.
- */
- static void
- pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, fz_matrix ctm)
- {
- gs->ctm = ctm;
- gs->clip_depth = 0;
- gs->stroke_state = fz_new_stroke_state(ctx);
- gs->stroke.kind = PDF_MAT_COLOR;
- gs->stroke.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
- gs->stroke.v[0] = 0;
- gs->stroke.pattern = NULL;
- gs->stroke.shade = NULL;
- gs->stroke.alpha = 1;
- gs->stroke.gstate_num = -1;
- gs->fill.kind = PDF_MAT_COLOR;
- gs->fill.colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
- gs->fill.v[0] = 0;
- gs->fill.pattern = NULL;
- gs->fill.shade = NULL;
- gs->fill.alpha = 1;
- gs->fill.gstate_num = -1;
- gs->text.char_space = 0;
- gs->text.word_space = 0;
- gs->text.scale = 1;
- gs->text.leading = 0;
- gs->text.font = NULL;
- gs->text.size = -1;
- gs->text.render = 0;
- gs->text.rise = 0;
- gs->blendmode = 0;
- gs->softmask = NULL;
- gs->softmask_cs = NULL;
- gs->softmask_resources = NULL;
- gs->softmask_ctm = fz_identity;
- gs->luminosity = 0;
- gs->fill.color_params = fz_default_color_params;
- gs->stroke.color_params = fz_default_color_params;
- gs->ismask = 0;
- }
- static void
- pdf_copy_gstate(fz_context *ctx, pdf_gstate *dst, pdf_gstate *src)
- {
- pdf_drop_gstate(ctx, dst);
- *dst = *src;
- pdf_keep_gstate(ctx, dst);
- }
- /*
- * Material state
- */
- static void
- pdf_set_colorspace(fz_context *ctx, pdf_run_processor *pr, int what, fz_colorspace *colorspace)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_material *mat;
- int n = fz_colorspace_n(ctx, colorspace);
- gstate = pdf_flush_text(ctx, pr);
- /* Don't change color if we're drawing an uncolored pattern tile! */
- if (gstate->ismask)
- return;
- mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke;
- fz_drop_colorspace(ctx, mat->colorspace);
- mat->kind = PDF_MAT_COLOR;
- mat->colorspace = fz_keep_colorspace(ctx, colorspace);
- mat->v[0] = 0;
- mat->v[1] = 0;
- mat->v[2] = 0;
- mat->v[3] = 1;
- if (pdf_is_tint_colorspace(ctx, colorspace))
- {
- int i;
- for (i = 0; i < n; i++)
- mat->v[i] = 1.0f;
- }
- }
- static void
- pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v)
- {
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_material *mat;
- gstate = pdf_flush_text(ctx, pr);
- /* Don't change color if we're drawing an uncolored pattern tile! */
- if (gstate->ismask)
- return;
- mat = what == PDF_FILL ? &gstate->fill : &gstate->stroke;
- switch (mat->kind)
- {
- case PDF_MAT_PATTERN:
- case PDF_MAT_COLOR:
- fz_clamp_color(ctx, mat->colorspace, v, mat->v);
- break;
- default:
- fz_warn(ctx, "color incompatible with material");
- }
- mat->gstate_num = pr->gparent;
- }
- static void
- pdf_set_shade(fz_context *ctx, pdf_run_processor *pr, int what, fz_shade *shade)
- {
- pdf_gstate *gs;
- pdf_material *mat;
- gs = pdf_flush_text(ctx, pr);
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
- fz_drop_shade(ctx, mat->shade);
- mat->kind = PDF_MAT_SHADE;
- mat->shade = fz_keep_shade(ctx, shade);
- mat->gstate_num = pr->gparent;
- }
- static void
- pdf_set_pattern(fz_context *ctx, pdf_run_processor *pr, int what, pdf_pattern *pat, float *v)
- {
- pdf_gstate *gs;
- pdf_material *mat;
- gs = pdf_flush_text(ctx, pr);
- mat = what == PDF_FILL ? &gs->fill : &gs->stroke;
- pdf_drop_pattern(ctx, mat->pattern);
- mat->pattern = NULL;
- mat->kind = PDF_MAT_PATTERN;
- if (pat)
- mat->pattern = pdf_keep_pattern(ctx, pat);
- if (v)
- pdf_set_color(ctx, pr, what, v);
- mat->gstate_num = pr->gparent;
- }
- static void
- begin_metatext(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_obj *mcid, fz_metatext meta, pdf_obj *name)
- {
- pdf_obj *text = pdf_dict_get(ctx, val, name);
- if (!text)
- text = pdf_dict_get(ctx, mcid, name);
- if (!text)
- return;
- pdf_flush_text(ctx, proc);
- fz_begin_metatext(ctx, proc->dev, meta, pdf_to_text_string(ctx, text));
- }
- static void
- end_metatext(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_obj *mcid, pdf_obj *name)
- {
- pdf_obj *text = pdf_dict_get(ctx, val, name);
- if (!text)
- text = pdf_dict_get(ctx, mcid, name);
- if (!text)
- return;
- pdf_flush_text(ctx, proc);
- fz_end_metatext(ctx, proc->dev);
- }
- static void
- begin_oc(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_cycle_list *cycle_up)
- {
- /* val has been resolved to a dict for us by the originally specified name
- * having been looked up in Properties already for us. Either there will
- * be a Name entry, or there will be an OCGs and it'll be a group one. */
- pdf_cycle_list cycle;
- pdf_obj *obj;
- int i, n;
- if (pdf_cycle(ctx, &cycle, cycle_up, val))
- return;
- obj = pdf_dict_get(ctx, val, PDF_NAME(Name));
- if (obj)
- {
- const char *name = "";
- pdf_flush_text(ctx, proc);
- if (pdf_is_name(ctx, obj))
- name = pdf_to_name(ctx, obj);
- else if (pdf_is_string(ctx, obj))
- name = pdf_to_text_string(ctx, obj);
- push_begin_layer(ctx, proc, name);
- return;
- }
- obj = pdf_dict_get(ctx, val, PDF_NAME(OCGs));
- n = pdf_array_len(ctx, obj);
- for (i = 0; i < n; i++)
- {
- begin_oc(ctx, proc, pdf_array_get(ctx, obj, i), &cycle);
- }
- }
- static void
- end_oc(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val, pdf_cycle_list *cycle_up)
- {
- /* val has been resolved to a dict for us by the originally specified name
- * having been looked up in Properties already for us. Either there will
- * be a Name entry, or there will be an OCGs and it'll be a group one. */
- pdf_cycle_list cycle;
- pdf_obj *obj;
- int i, n;
- if (pdf_cycle(ctx, &cycle, cycle_up, val))
- return;
- obj = pdf_dict_get(ctx, val, PDF_NAME(Name));
- if (obj)
- {
- flush_begin_layer(ctx, proc);
- do_end_layer(ctx, proc);
- return;
- }
- obj = pdf_dict_get(ctx, val, PDF_NAME(OCGs));
- n = pdf_array_len(ctx, obj);
- for (i = n-1; i >= 0; i--)
- {
- end_oc(ctx, proc, pdf_array_get(ctx, obj, i), &cycle);
- }
- }
- static void
- begin_layer(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val)
- {
- /* val has been resolved to a dict for us by the originally specified name
- * having been looked up in Properties already for us. Go with the 'Title'
- * entry. */
- pdf_obj *obj = pdf_dict_get(ctx, val, PDF_NAME(Title));
- if (obj)
- {
- pdf_flush_text(ctx, proc);
- push_begin_layer(ctx, proc, pdf_to_text_string(ctx, obj));
- }
- }
- static void
- end_layer(fz_context *ctx, pdf_run_processor *proc, pdf_obj *val)
- {
- /* val has been resolved to a dict for us by the originally specified name
- * having been looked up in Properties already for us. Go with the 'Title'
- * entry. */
- pdf_obj *obj = pdf_dict_get(ctx, val, PDF_NAME(Title));
- if (obj)
- {
- do_end_layer(ctx, proc);
- }
- }
- #ifdef DEBUG_STRUCTURE
- static void
- structure_dump(fz_context *ctx, const char *str, pdf_obj *obj)
- {
- fprintf(stderr, "%s STACK=", str);
- if (obj == NULL)
- {
- fprintf(stderr, "empty\n");
- return;
- }
- do
- {
- pdf_obj *s = pdf_dict_get(ctx, obj, PDF_NAME(S));
- int n = pdf_to_num(ctx, obj);
- fprintf(stderr, " %d", n);
- if (s)
- fprintf(stderr, "[%s]", pdf_to_name(ctx, s));
- obj = pdf_dict_get(ctx, obj, PDF_NAME(P));
- }
- while (obj);
- fprintf(stderr, "\n");
- }
- #endif
- static void
- pop_structure_to(fz_context *ctx, pdf_run_processor *proc, pdf_obj *common)
- {
- pdf_obj *struct_tree_root = pdf_dict_getl(ctx, pdf_trailer(ctx, proc->doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), NULL);
- #ifdef DEBUG_STRUCTURE
- structure_dump(ctx, "pop_structure_to (before)", proc->mcid_sent);
- {
- int n = pdf_to_num(ctx, common);
- fprintf(stderr, "Popping until %d\n", n);
- }
- #endif
- while (proc->mcid_sent != NULL && pdf_objcmp(ctx, proc->mcid_sent, common))
- {
- pdf_obj *p = pdf_dict_get(ctx, proc->mcid_sent, PDF_NAME(P));
- pdf_obj *tag = pdf_dict_get(ctx, proc->mcid_sent, PDF_NAME(S));
- fz_structure standard = pdf_structure_type(ctx, proc->role_map, tag);
- #ifdef DEBUG_STRUCTURE
- fprintf(stderr, "sending pop [tag=%s][std=%d]\n", pdf_to_name(ctx, tag) ? pdf_to_name(ctx, tag) : "null", standard);
- #endif
- if (standard != FZ_STRUCTURE_INVALID)
- fz_end_structure(ctx, proc->dev);
- pdf_drop_obj(ctx, proc->mcid_sent);
- proc->mcid_sent = pdf_keep_obj(ctx, p);
- if (!pdf_objcmp(ctx, p, struct_tree_root))
- {
- pdf_drop_obj(ctx, proc->mcid_sent);
- proc->mcid_sent = NULL;
- break;
- }
- }
- #ifdef DEBUG_STRUCTURE
- structure_dump(ctx, "pop_structure_to (after)", proc->mcid_sent);
- #endif
- }
- static void
- pop_any_pending_mcid_changes(fz_context *ctx, pdf_run_processor *pr)
- {
- if (pr->pending_mcid_pop == NULL)
- return;
- pop_structure_to(ctx, pr, pr->pending_mcid_pop);
- pr->pending_mcid_pop = NULL;
- }
- struct line
- {
- pdf_obj *obj;
- struct line *child;
- };
- static pdf_obj *
- find_most_recent_common_ancestor_imp(fz_context *ctx, pdf_obj *a, struct line *line_a, pdf_obj *b, struct line *line_b, pdf_cycle_list *cycle_up_a, pdf_cycle_list *cycle_up_b)
- {
- struct line line;
- pdf_obj *common = NULL;
- pdf_cycle_list cycle;
- pdf_obj *parent;
- /* First ascend one lineage. */
- if (pdf_is_dict(ctx, a))
- {
- if (pdf_cycle(ctx, &cycle, cycle_up_a, a))
- fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in structure tree");
- line.obj = a;
- line.child = line_a;
- parent = pdf_dict_get(ctx, a, PDF_NAME(P));
- return find_most_recent_common_ancestor_imp(ctx, parent, &line, b, NULL, &cycle, NULL);
- }
- /* Then ascend the other lineage. */
- else if (pdf_is_dict(ctx, b))
- {
- if (pdf_cycle(ctx, &cycle, cycle_up_b, b))
- fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in structure tree");
- line.obj = b;
- line.child = line_b;
- parent = pdf_dict_get(ctx, b, PDF_NAME(P));
- return find_most_recent_common_ancestor_imp(ctx, a, line_a, parent, &line, cycle_up_a, &cycle);
- }
- /* Once both lineages are know, traverse top-down to find most recent common ancestor. */
- while (line_a && line_b && !pdf_objcmp(ctx, line_a->obj, line_b->obj))
- {
- common = line_a->obj;
- line_a = line_a->child;
- line_b = line_b->child;
- }
- return common;
- }
- static pdf_obj *
- find_most_recent_common_ancestor(fz_context *ctx, pdf_obj *a, pdf_obj *b)
- {
- if (!pdf_is_dict(ctx, a) || !pdf_is_dict(ctx, b))
- return NULL;
- return find_most_recent_common_ancestor_imp(ctx, a, NULL, b, NULL, NULL, NULL);
- }
- static int
- get_struct_index(fz_context *ctx, pdf_obj *send)
- {
- pdf_obj *p = pdf_dict_get(ctx, send, PDF_NAME(P));
- pdf_obj *k;
- int i, n;
- if (p == NULL)
- return 0; /* Presumably the StructTreeRoot */
- /* So, get the kids array. */
- k = pdf_dict_get(ctx, p, PDF_NAME(K));
- n = pdf_array_len(ctx, k);
- if (n == 0)
- {
- /* Not an array, presumably a singleton. */
- if (pdf_objcmp(ctx, k, send) == 0)
- return 0;
- return -1;
- }
- for (i = 0; i < n; i++)
- {
- if (pdf_objcmp(ctx, pdf_array_get(ctx, k, i), send) == 0)
- return i;
- }
- return -1;
- }
- static int
- send_begin_structure(fz_context *ctx, pdf_run_processor *proc, pdf_obj *mc_dict)
- {
- pdf_obj *common = NULL;
- #ifdef DEBUG_STRUCTURE
- fprintf(stderr, "send_begin_structure %d\n", pdf_to_num(ctx, mc_dict));
- structure_dump(ctx, "on entry", proc->mcid_sent);
- #endif
- /* We are currently nested in A,B,C,...E,F,mcid_sent. We want to update to
- * being in A,B,C,...G,H,mc_dict. So we need to find the lowest common point. */
- common = find_most_recent_common_ancestor(ctx, proc->mcid_sent, mc_dict);
- /* So, we need to pop everything up to common (i.e. everything below common will be closed). */
- pop_structure_to(ctx, proc, common);
- #ifdef DEBUG_STRUCTURE
- structure_dump(ctx, "after popping", proc->mcid_sent);
- #endif
- /* Now we need to send everything between common (proc->mcid_sent) and mc_dict.
- * Again, n^2 will do... */
- while (pdf_objcmp(ctx, proc->mcid_sent, mc_dict))
- {
- pdf_obj *send = mc_dict;
- fz_structure standard;
- pdf_obj *tag;
- int idx;
- pdf_obj *slowptr = send;
- int slow = 0;
- /* Run up the ancestor stack, looking for the first child of mcid_sent.
- * That's the one we need to send next. */
- while (1) {
- pdf_obj *p = pdf_dict_get(ctx, send, PDF_NAME(P));
- /* If we ever fail to find a dict, then do not step down lest
- * we can't get back later! */
- if (!pdf_is_dict(ctx, send))
- {
- fz_warn(ctx, "Bad parent link in structure tree. Ignoring structure.");
- proc->broken_struct_tree = 1;
- return 0;
- }
- /* If p is the one we last sent, then we want to send 'send'
- * next. Exit the loop. */
- if (!pdf_objcmp(ctx, p, proc->mcid_sent))
- break;
- /* We need to go at least one step further up the stack. */
- send = p;
- /* Check for a loop in the parent tree. */
- slow ^= 1;
- if (slow == 0)
- slowptr = pdf_dict_get(ctx, slowptr, PDF_NAME(P));
- if (!pdf_objcmp(ctx, send, slowptr))
- {
- fz_warn(ctx, "Loop found in structure tree. Ignoring structure.");
- proc->broken_struct_tree = 1;
- return 0;
- }
- }
- idx = get_struct_index(ctx, send);
- tag = pdf_dict_get(ctx, send, PDF_NAME(S));
- standard = pdf_structure_type(ctx, proc->role_map, tag);
- #ifdef DEBUG_STRUCTURE
- fprintf(stderr, "sending %d[idx=%d][tag=%s][std=%d]\n", pdf_to_num(ctx, send), idx, pdf_to_name(ctx, tag) ? pdf_to_name(ctx, tag) : "null", standard);
- #endif
- if (standard != FZ_STRUCTURE_INVALID)
- fz_begin_structure(ctx, proc->dev, standard, pdf_to_name(ctx, tag), idx);
- pdf_drop_obj(ctx, proc->mcid_sent);
- proc->mcid_sent = pdf_keep_obj(ctx, send);
- }
- #ifdef DEBUG_STRUCTURE
- structure_dump(ctx, "on exit", proc->mcid_sent);
- #endif
- return 1;
- }
- static void
- push_marked_content(fz_context *ctx, pdf_run_processor *proc, const char *tagstr, pdf_obj *val)
- {
- pdf_obj *tag;
- marked_content_stack *mc = NULL;
- int drop_tag = 1;
- pdf_obj *mc_dict = NULL;
- /* Ignore any pending pops. */
- proc->pending_mcid_pop = NULL;
- /* Flush any pending text so it's not in the wrong layer. */
- pdf_flush_text(ctx, proc);
- if (!tagstr)
- tagstr = "Untitled";
- tag = pdf_new_name(ctx, tagstr);
- fz_var(drop_tag);
- fz_try(ctx)
- {
- /* First, push it on the stack. */
- mc = fz_malloc_struct(ctx, marked_content_stack);
- mc->next = proc->marked_content;
- mc->tag = tag;
- mc->val = pdf_keep_obj(ctx, val);
- mc->structure_pushed = 0;
- proc->marked_content = mc;
- drop_tag = 0;
- /* Check to see if val contains an MCID. */
- mc_dict = lookup_mcid(ctx, proc, val);
- /* Start any optional content layers. */
- if (pdf_name_eq(ctx, tag, PDF_NAME(OC)))
- begin_oc(ctx, proc, val, NULL);
- /* Special handling for common non-spec extension. */
- if (pdf_name_eq(ctx, tag, PDF_NAME(Layer)))
- begin_layer(ctx, proc, val);
- /* Structure */
- if (mc_dict && !proc->broken_struct_tree)
- {
- fz_try(ctx)
- mc->structure_pushed = send_begin_structure(ctx, proc, mc_dict);
- fz_catch(ctx)
- {
- fz_report_error(ctx);
- fz_warn(ctx, "structure tree broken, assume tree is missing");
- proc->broken_struct_tree = 1;
- }
- }
- /* Previously, I'd tried to send stuff like:
- * /Artifact <</Type/Pagination>>BDC
- * as a structure entry, lured by the fact that 'Artifact' is a
- * structure tag. I now believe this is wrong. Only stuff with
- * an MCID pointer should be sent using the structure mechanism.
- */
- /* ActualText */
- begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ACTUALTEXT, PDF_NAME(ActualText));
- /* Alt */
- begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ALT, PDF_NAME(Alt));
- /* Abbreviation */
- begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_ABBREVIATION, PDF_NAME(E));
- /* Title */
- begin_metatext(ctx, proc, val, mc_dict, FZ_METATEXT_TITLE, PDF_NAME(T));
- }
- fz_catch(ctx)
- {
- if (drop_tag)
- pdf_drop_obj(ctx, tag);
- fz_rethrow(ctx);
- }
- }
- static void
- pop_marked_content(fz_context *ctx, pdf_run_processor *proc, int neat)
- {
- marked_content_stack *mc = proc->marked_content;
- pdf_obj *val, *tag;
- pdf_obj *mc_dict = NULL;
- int pushed;
- if (mc == NULL)
- return;
- proc->marked_content = mc->next;
- tag = mc->tag;
- val = mc->val;
- pushed = mc->structure_pushed;
- fz_free(ctx, mc);
- /* If we're not interested in neatly closing any open layers etc
- * in the processor, (maybe we've had errors already), then just
- * exit here. */
- if (!neat)
- {
- pdf_drop_obj(ctx, tag);
- pdf_drop_obj(ctx, val);
- return;
- }
- /* Close structure/layers here, in reverse order to how we opened them. */
- fz_try(ctx)
- {
- /* Make sure that any pending text is written into the correct layer. */
- pdf_flush_text(ctx, proc);
- /* Check to see if val contains an MCID. */
- mc_dict = lookup_mcid(ctx, proc, val);
- /* Title */
- end_metatext(ctx, proc, val, mc_dict, PDF_NAME(T));
- /* Abbreviation */
- end_metatext(ctx, proc, val, mc_dict, PDF_NAME(E));
- /* Alt */
- end_metatext(ctx, proc, val, mc_dict, PDF_NAME(Alt));
- /* ActualText */
- end_metatext(ctx, proc, val, mc_dict, PDF_NAME(ActualText));
- /* Structure */
- if (mc_dict && !proc->broken_struct_tree && pushed)
- {
- /* Is there a nested mc_dict? If so we want to pop back to that.
- * If not, we want to pop back to the top.
- * proc->marked_content = the previous one, but maybe not the
- * previous one with an mc_dict. So we may need to search further.
- */
- pdf_obj *previous_mcid = NULL;
- marked_content_stack *mc_with_mcid = proc->marked_content;
- while (mc_with_mcid)
- {
- previous_mcid = lookup_mcid(ctx, proc, mc_with_mcid->val);
- if (previous_mcid != NULL)
- break;
- mc_with_mcid = mc_with_mcid->next;
- }
- proc->pending_mcid_pop = previous_mcid;
- }
- /* Finally, close any layers. */
- if (pdf_name_eq(ctx, tag, PDF_NAME(Layer)))
- end_layer(ctx, proc, val);
- if (pdf_name_eq(ctx, tag, PDF_NAME(OC)))
- end_oc(ctx, proc, val, NULL);
- }
- fz_always(ctx)
- {
- pdf_drop_obj(ctx, tag);
- pdf_drop_obj(ctx, val);
- }
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- static void
- clear_marked_content(fz_context *ctx, pdf_run_processor *pr)
- {
- if (pr->marked_content == NULL)
- return;
- fz_try(ctx)
- while (pr->marked_content)
- pop_marked_content(ctx, pr, 1);
- fz_always(ctx)
- while (pr->marked_content)
- pop_marked_content(ctx, pr, 0);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- static void
- pdf_run_xobject(fz_context *ctx, pdf_run_processor *pr, pdf_obj *xobj, pdf_obj *page_resources, fz_matrix transform, int is_smask)
- {
- pdf_cycle_list cycle_here;
- pdf_gstate *gstate = NULL;
- int oldtop = 0;
- int oldbot = -1;
- softmask_save softmask = { NULL };
- int gparent_save;
- fz_matrix gparent_save_ctm;
- pdf_obj *resources;
- fz_rect xobj_bbox;
- fz_matrix xobj_matrix;
- int transparency = 0;
- pdf_document *doc;
- fz_colorspace *cs = NULL;
- fz_default_colorspaces *save_default_cs = NULL;
- fz_default_colorspaces *xobj_default_cs = NULL;
- marked_content_stack *save_marked_content = NULL;
- int save_struct_parent;
- pdf_obj *oc;
- /* Avoid infinite recursion */
- pdf_cycle_list *cycle_up = pr->cycle;
- if (xobj == NULL || pdf_cycle(ctx, &cycle_here, cycle_up, xobj))
- return;
- pr->cycle = &cycle_here;
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- fz_var(cs);
- fz_var(xobj_default_cs);
- gparent_save = pr->gparent;
- pr->gparent = pr->gtop;
- oldtop = pr->gtop;
- save_default_cs = pr->default_cs;
- save_marked_content = pr->marked_content;
- pr->marked_content = NULL;
- save_struct_parent = pr->struct_parent;
- fz_try(ctx)
- {
- pr->struct_parent = pdf_dict_get_int_default(ctx, xobj, PDF_NAME(StructParent), -1);
- oc = pdf_dict_get(ctx, xobj, PDF_NAME(OC));
- if (oc)
- begin_oc(ctx, pr, oc, NULL);
- pdf_gsave(ctx, pr);
- gstate = pr->gstate + pr->gtop;
- xobj_bbox = pdf_xobject_bbox(ctx, xobj);
- xobj_matrix = pdf_xobject_matrix(ctx, xobj);
- transparency = pdf_xobject_transparency(ctx, xobj);
- /* apply xobject's transform matrix */
- transform = fz_concat(xobj_matrix, transform);
- gstate->ctm = fz_concat(transform, gstate->ctm);
- /* The gparent is updated with the modified ctm */
- gparent_save_ctm = pr->gstate[pr->gparent].ctm;
- pr->gstate[pr->gparent].ctm = gstate->ctm;
- /* apply soft mask, create transparency group and reset state */
- if (transparency)
- {
- int isolated = pdf_xobject_isolated(ctx, xobj);
- fz_rect bbox = fz_transform_rect(xobj_bbox, gstate->ctm);
- gstate = begin_softmask(ctx, pr, &softmask, bbox);
- if (isolated)
- cs = pdf_xobject_colorspace(ctx, xobj);
- fz_begin_group(ctx, pr->dev, bbox,
- cs,
- (is_smask ? 1 : isolated),
- pdf_xobject_knockout(ctx, xobj),
- gstate->blendmode, gstate->fill.alpha);
- gstate->blendmode = 0;
- gstate->stroke.alpha = 1;
- gstate->fill.alpha = 1;
- }
- pdf_gsave(ctx, pr); /* Save here so the clippath doesn't persist */
- /* clip to the bounds */
- fz_moveto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y0);
- fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y0);
- fz_lineto(ctx, pr->path, xobj_bbox.x1, xobj_bbox.y1);
- fz_lineto(ctx, pr->path, xobj_bbox.x0, xobj_bbox.y1);
- fz_closepath(ctx, pr->path);
- pr->clip = 1;
- pdf_show_path(ctx, pr, 0, 0, 0, 0);
- /* run contents */
- resources = pdf_xobject_resources(ctx, xobj);
- if (!resources)
- resources = page_resources;
- fz_try(ctx)
- xobj_default_cs = pdf_update_default_colorspaces(ctx, pr->default_cs, resources);
- fz_catch(ctx)
- {
- fz_rethrow_unless(ctx, FZ_ERROR_TRYLATER);
- fz_ignore_error(ctx);
- if (pr->cookie)
- pr->cookie->incomplete = 1;
- }
- if (xobj_default_cs != save_default_cs)
- {
- fz_set_default_colorspaces(ctx, pr->dev, xobj_default_cs);
- pr->default_cs = xobj_default_cs;
- }
- doc = pdf_get_bound_document(ctx, xobj);
- oldbot = pr->gbot;
- pr->gbot = pr->gtop;
- pdf_process_contents(ctx, (pdf_processor*)pr, doc, resources, xobj, pr->cookie, NULL);
- /* Undo any gstate mismatches due to the pdf_process_contents call */
- if (oldbot != -1)
- {
- while (pr->gtop > pr->gbot)
- {
- pdf_grestore(ctx, pr);
- }
- pr->gbot = oldbot;
- }
- pdf_grestore(ctx, pr); /* Remove the state we pushed for the clippath */
- /* wrap up transparency stacks */
- if (transparency)
- {
- fz_end_group(ctx, pr->dev);
- end_softmask(ctx, pr, &softmask);
- }
- pr->gstate[pr->gparent].ctm = gparent_save_ctm;
- pr->gparent = gparent_save;
- while (oldtop < pr->gtop)
- pdf_grestore(ctx, pr);
- if (oc)
- end_oc(ctx, pr, oc, NULL);
- if (xobj_default_cs != save_default_cs)
- {
- fz_set_default_colorspaces(ctx, pr->dev, save_default_cs);
- }
- }
- fz_always(ctx)
- {
- clear_marked_content(ctx, pr);
- pr->marked_content = save_marked_content;
- pr->default_cs = save_default_cs;
- fz_drop_default_colorspaces(ctx, xobj_default_cs);
- fz_drop_colorspace(ctx, cs);
- pr->cycle = cycle_up;
- pr->struct_parent = save_struct_parent;
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, softmask.softmask);
- fz_drop_colorspace(ctx, softmask.softmask_cs);
- pdf_drop_obj(ctx, softmask.page_resources);
- /* Note: Any SYNTAX errors should have been swallowed
- * by pdf_process_contents, but in case any escape from other
- * functions, recast the error type here to be safe. */
- fz_morph_error(ctx, FZ_ERROR_SYNTAX, FZ_ERROR_FORMAT);
- fz_rethrow(ctx);
- }
- }
- /* general graphics state */
- static void pdf_run_w(fz_context *ctx, pdf_processor *proc, float linewidth)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- pr->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED;
- gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
- gstate->stroke_state->linewidth = linewidth;
- }
- static void pdf_run_j(fz_context *ctx, pdf_processor *proc, int linejoin)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- pr->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED;
- gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
- gstate->stroke_state->linejoin = linejoin;
- }
- static void pdf_run_J(fz_context *ctx, pdf_processor *proc, int linecap)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- pr->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED);
- gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
- gstate->stroke_state->start_cap = linecap;
- gstate->stroke_state->dash_cap = linecap;
- gstate->stroke_state->end_cap = linecap;
- }
- static void pdf_run_M(fz_context *ctx, pdf_processor *proc, float miterlimit)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- pr->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED;
- gstate->stroke_state = fz_unshare_stroke_state(ctx, gstate->stroke_state);
- gstate->stroke_state->miterlimit = miterlimit;
- }
- static void pdf_run_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- int len, i;
- pr->dev->flags &= ~FZ_DEVFLAG_DASH_PATTERN_UNDEFINED;
- len = pdf_array_len(ctx, array);
- gstate->stroke_state = fz_unshare_stroke_state_with_dash_len(ctx, gstate->stroke_state, len);
- for (i = 0; i < len; i++)
- gstate->stroke_state->dash_list[i] = pdf_array_get_real(ctx, array, i);
- gstate->stroke_state->dash_phase = phase;
- }
- static void pdf_run_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->fill.color_params.ri = fz_lookup_rendering_intent(intent);
- gstate->stroke.color_params.ri = gstate->fill.color_params.ri;
- }
- static void pdf_run_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->stroke.color_params.op = b;
- gstate->fill.color_params.op = b;
- }
- static void pdf_run_gs_op(fz_context *ctx, pdf_processor *proc, int b)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->fill.color_params.op = b;
- }
- static void pdf_run_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->stroke.color_params.opm = i;
- gstate->fill.color_params.opm = i;
- }
- static void pdf_run_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *obj)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- int on = pdf_name_eq(ctx, obj, PDF_NAME(ON));
- /* The spec says that "ON" means on, "OFF" means "Off", and
- * "Default" or anything else means "Meh, do what you want." */
- gstate->stroke.color_params.bp = on;
- gstate->fill.color_params.bp = on;
- }
- static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness)
- {
- }
- static void pdf_run_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
- {
- }
- static void pdf_run_gs_end(fz_context *ctx, pdf_processor *proc)
- {
- }
- /* transparency graphics state */
- static void pdf_run_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->blendmode = fz_lookup_blendmode(blendmode);
- }
- static void pdf_run_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->stroke.alpha = fz_clamp(alpha, 0, 1);
- }
- static void pdf_run_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- gstate->fill.alpha = fz_clamp(alpha, 0, 1);
- }
- static void pdf_run_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, fz_colorspace *smask_cs, float *bc, int luminosity, pdf_obj *tr)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- int i;
- if (gstate->softmask)
- {
- pdf_drop_obj(ctx, gstate->softmask);
- gstate->softmask = NULL;
- fz_drop_colorspace(ctx, gstate->softmask_cs);
- gstate->softmask_cs = NULL;
- pdf_drop_obj(ctx, gstate->softmask_resources);
- gstate->softmask_resources = NULL;
- }
- if (smask)
- {
- int cs_n = fz_colorspace_n(ctx, smask_cs);
- gstate->softmask_ctm = gstate->ctm;
- gstate->softmask = pdf_keep_obj(ctx, smask);
- gstate->softmask_cs = fz_keep_colorspace(ctx, smask_cs);
- gstate->softmask_resources = pdf_keep_obj(ctx, pr->rstack->resources);
- pdf_drop_obj(ctx, gstate->softmask_tr);
- gstate->softmask_tr = NULL;
- if (tr)
- gstate->softmask_tr = pdf_keep_obj(ctx, tr);
- for (i = 0; i < cs_n; ++i)
- gstate->softmask_bc[i] = bc[i];
- gstate->luminosity = luminosity;
- }
- }
- /* special graphics state */
- static void pdf_run_q(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- flush_begin_layer(ctx, pr);
- pdf_gsave(ctx, pr);
- }
- static void pdf_run_Q(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_flush_text(ctx, pr);
- pdf_grestore(ctx, pr);
- }
- static void pdf_run_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pdf_flush_text(ctx, pr);
- fz_matrix m;
- m.a = a;
- m.b = b;
- m.c = c;
- m.d = d;
- m.e = e;
- m.f = f;
- gstate->ctm = fz_concat(m, gstate->ctm);
- }
- /* path construction */
- static void pdf_run_m(fz_context *ctx, pdf_processor *proc, float x, float y)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_moveto(ctx, pr->path, x, y);
- }
- static void pdf_run_l(fz_context *ctx, pdf_processor *proc, float x, float y)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_lineto(ctx, pr->path, x, y);
- }
- static void pdf_run_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_curveto(ctx, pr->path, x1, y1, x2, y2, x3, y3);
- }
- static void pdf_run_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_curvetov(ctx, pr->path, x2, y2, x3, y3);
- }
- static void pdf_run_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_curvetoy(ctx, pr->path, x1, y1, x3, y3);
- }
- static void pdf_run_h(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_closepath(ctx, pr->path);
- }
- static void pdf_run_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_rectto(ctx, pr->path, x, y, x+w, y+h);
- }
- /* path painting */
- static void pdf_run_S(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 0, 1, 0);
- }
- static void pdf_run_s(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 1, 0, 1, 0);
- }
- static void pdf_run_F(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 1, 0, 0);
- }
- static void pdf_run_f(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 1, 0, 0);
- }
- static void pdf_run_fstar(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 1, 0, 1);
- }
- static void pdf_run_B(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 1, 1, 0);
- }
- static void pdf_run_Bstar(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 1, 1, 1);
- }
- static void pdf_run_b(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 1, 1, 1, 0);
- }
- static void pdf_run_bstar(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 1, 1, 1, 1);
- }
- static void pdf_run_n(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_path(ctx, pr, 0, 0, 0, 0);
- }
- /* clipping paths */
- static void pdf_run_W(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_flush_text(ctx, pr);
- pr->clip = 1;
- pr->clip_even_odd = 0;
- }
- static void pdf_run_Wstar(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_flush_text(ctx, pr);
- pr->clip = 1;
- pr->clip_even_odd = 1;
- }
- /* text objects */
- static void pdf_run_BT(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->tos.tm = fz_identity;
- pr->tos.tlm = fz_identity;
- pr->bidi = 0;
- }
- static void pdf_run_ET(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_flush_text(ctx, pr);
- }
- /* text state */
- static void pdf_run_Tc(fz_context *ctx, pdf_processor *proc, float charspace)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.char_space = charspace;
- }
- static void pdf_run_Tw(fz_context *ctx, pdf_processor *proc, float wordspace)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.word_space = wordspace;
- }
- static void pdf_run_Tz(fz_context *ctx, pdf_processor *proc, float scale)
- {
- /* scale is as written in the file. It is 100 times smaller in
- * the gstate. */
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.scale = scale / 100;
- }
- static void pdf_run_TL(fz_context *ctx, pdf_processor *proc, float leading)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.leading = leading;
- }
- static void pdf_run_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_drop_font(ctx, gstate->text.font);
- gstate->text.font = pdf_keep_font(ctx, font);
- gstate->text.size = size;
- }
- static void pdf_run_Tr(fz_context *ctx, pdf_processor *proc, int render)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.render = render;
- }
- static void pdf_run_Ts(fz_context *ctx, pdf_processor *proc, float rise)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.rise = rise;
- }
- /* text positioning */
- static void pdf_run_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_tos_translate(&pr->tos, tx, ty);
- }
- static void pdf_run_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.leading = -ty;
- pdf_tos_translate(&pr->tos, tx, ty);
- }
- static void pdf_run_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_tos_set_matrix(&pr->tos, a, b, c, d, e, f);
- }
- static void pdf_run_Tstar(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_tos_newline(&pr->tos, gstate->text.leading);
- }
- /* text showing */
- static void pdf_run_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *obj)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_text(ctx, pr, obj);
- }
- static void pdf_run_Tj(fz_context *ctx, pdf_processor *proc, char *string, size_t string_len)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_string(ctx, pr, (unsigned char *)string, string_len);
- }
- static void pdf_run_squote(fz_context *ctx, pdf_processor *proc, char *string, size_t string_len)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- pdf_tos_newline(&pr->tos, gstate->text.leading);
- pdf_show_string(ctx, pr, (unsigned char*)string, string_len);
- }
- static void pdf_run_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *string, size_t string_len)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_gstate *gstate = pr->gstate + pr->gtop;
- gstate->text.word_space = aw;
- gstate->text.char_space = ac;
- pdf_tos_newline(&pr->tos, gstate->text.leading);
- pdf_show_string(ctx, pr, (unsigned char*)string, string_len);
- }
- /* type 3 fonts */
- static void pdf_run_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags |= FZ_DEVFLAG_COLOR;
- }
- static void pdf_run_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags |= FZ_DEVFLAG_MASK | FZ_DEVFLAG_BBOX_DEFINED;
- pr->dev->d1_rect.x0 = fz_min(llx, urx);
- pr->dev->d1_rect.y0 = fz_min(lly, ury);
- pr->dev->d1_rect.x1 = fz_max(llx, urx);
- pr->dev->d1_rect.y1 = fz_max(lly, ury);
- }
- /* color */
- static void pdf_run_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- if (!strcmp(name, "Pattern"))
- pdf_set_pattern(ctx, pr, PDF_STROKE, NULL, NULL);
- else
- pdf_set_colorspace(ctx, pr, PDF_STROKE, colorspace);
- }
- static void pdf_run_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *colorspace)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- if (!strcmp(name, "Pattern"))
- pdf_set_pattern(ctx, pr, PDF_FILL, NULL, NULL);
- else
- pdf_set_colorspace(ctx, pr, PDF_FILL, colorspace);
- }
- static void pdf_run_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_color(ctx, pr, PDF_STROKE, color);
- }
- static void pdf_run_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_color(ctx, pr, PDF_FILL, color);
- }
- static void pdf_run_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_pattern(ctx, pr, PDF_STROKE, pat, color);
- }
- static void pdf_run_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_pattern(ctx, pr, PDF_FILL, pat, color);
- }
- static void pdf_run_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_shade(ctx, pr, PDF_STROKE, shade);
- }
- static void pdf_run_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_shade(ctx, pr, PDF_FILL, shade);
- }
- static void pdf_run_G(fz_context *ctx, pdf_processor *proc, float g)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_gray(ctx));
- pdf_set_color(ctx, pr, PDF_STROKE, &g);
- }
- static void pdf_run_g(fz_context *ctx, pdf_processor *proc, float g)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_gray(ctx));
- pdf_set_color(ctx, pr, PDF_FILL, &g);
- }
- static void pdf_run_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- float color[4] = {c, m, y, k};
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_cmyk(ctx));
- pdf_set_color(ctx, pr, PDF_STROKE, color);
- }
- static void pdf_run_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- float color[4] = {c, m, y, k};
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_cmyk(ctx));
- pdf_set_color(ctx, pr, PDF_FILL, color);
- }
- static void pdf_run_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- float color[3] = {r, g, b};
- pr->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_STROKE, fz_device_rgb(ctx));
- pdf_set_color(ctx, pr, PDF_STROKE, color);
- }
- static void pdf_run_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- float color[3] = {r, g, b};
- pr->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED;
- if (pr->dev->flags & FZ_DEVFLAG_MASK)
- return;
- pdf_set_colorspace(ctx, pr, PDF_FILL, fz_device_rgb(ctx));
- pdf_set_color(ctx, pr, PDF_FILL, color);
- }
- /* shadings, images, xobjects */
- static void pdf_run_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_image(ctx, pr, image);
- }
- static void pdf_run_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pop_any_pending_mcid_changes(ctx, pr);
- flush_begin_layer(ctx, pr);
- pdf_show_shade(ctx, pr, shade);
- }
- static void pdf_run_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_show_image(ctx, pr, image);
- }
- static void pdf_run_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, pr->rstack->resources, fz_identity, 0);
- }
- /* marked content */
- static void pdf_run_BMC(fz_context *ctx, pdf_processor *proc, const char *tag)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- push_marked_content(ctx, pr, tag, NULL);
- }
- static void pdf_run_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- push_marked_content(ctx, pr, tag, cooked);
- }
- static void pdf_run_EMC(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pop_marked_content(ctx, pr, 1);
- }
- static void pdf_run_MP(fz_context *ctx, pdf_processor *proc, const char *tag)
- {
- pdf_run_BMC(ctx, proc, tag);
- pdf_run_EMC(ctx, proc);
- }
- static void pdf_run_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
- {
- pdf_run_BDC(ctx, proc, tag, raw, cooked);
- pdf_run_EMC(ctx, proc);
- }
- /* compatibility */
- static void pdf_run_BX(fz_context *ctx, pdf_processor *proc)
- {
- }
- static void pdf_run_EX(fz_context *ctx, pdf_processor *proc)
- {
- }
- static void pdf_run_END(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- pdf_flush_text(ctx, pr);
- }
- static void
- pdf_close_run_processor(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- while (pr->gtop)
- pdf_grestore(ctx, pr);
- while (pr->nest_depth > 0)
- {
- if (pr->nest_mark[pr->nest_depth-1] < 0)
- {
- /* It's a clip. */
- fz_pop_clip(ctx, pr->dev);
- pr->nest_mark[pr->nest_depth-1]++;
- if (pr->nest_mark[pr->nest_depth-1] == 0)
- pr->nest_depth--;
- }
- else
- {
- /* It's a layer. */
- fz_end_layer(ctx, pr->dev);
- pr->nest_depth--;
- }
- }
- pop_structure_to(ctx, pr, NULL);
- clear_marked_content(ctx, pr);
- }
- static void
- pdf_drop_run_processor(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- while (pr->gtop >= 0)
- {
- pdf_drop_gstate(ctx, &pr->gstate[pr->gtop]);
- pr->gtop--;
- }
- fz_drop_path(ctx, pr->path);
- fz_drop_text(ctx, pr->tos.text);
- fz_drop_default_colorspaces(ctx, pr->default_cs);
- fz_free(ctx, pr->gstate);
- while (pr->rstack)
- {
- resources_stack *stk = pr->rstack;
- pr->rstack = stk->next;
- pdf_drop_obj(ctx, stk->resources);
- fz_free(ctx, stk);
- }
- while (pr->begin_layer)
- {
- begin_layer_stack *stk = pr->begin_layer;
- pr->begin_layer = stk->next;
- fz_free(ctx, stk->layer);
- fz_free(ctx, stk);
- }
- while (pr->marked_content)
- pop_marked_content(ctx, pr, 0);
- pdf_drop_obj(ctx, pr->mcid_sent);
- pdf_drop_document(ctx, pr->doc);
- pdf_drop_obj(ctx, pr->role_map);
- }
- static void
- pdf_run_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *resources)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- resources_stack *stk = fz_malloc_struct(ctx, resources_stack);
- stk->next = pr->rstack;
- pr->rstack = stk;
- stk->resources = pdf_keep_obj(ctx, resources);
- }
- static pdf_obj *
- pdf_run_pop_resources(fz_context *ctx, pdf_processor *proc)
- {
- pdf_run_processor *pr = (pdf_run_processor *)proc;
- resources_stack *stk = pr->rstack;
- if (stk)
- {
- pr->rstack = stk->next;
- pdf_drop_obj(ctx, stk->resources);
- fz_free(ctx, stk);
- }
- return NULL;
- }
- /*
- Create a new "run" processor. This maps
- from PDF operators to fz_device level calls.
- dev: The device to which the resulting device calls are to be
- sent.
- ctm: The initial transformation matrix to use.
- usage: A NULL terminated string that describes the 'usage' of
- this interpretation. Typically 'View', though 'Print' is also
- defined within the PDF reference manual, and others are possible.
- gstate: The initial graphics state.
- */
- pdf_processor *
- pdf_new_run_processor(fz_context *ctx, pdf_document *doc, fz_device *dev, fz_matrix ctm, int struct_parent, const char *usage, pdf_gstate *gstate, fz_default_colorspaces *default_cs, fz_cookie *cookie, pdf_gstate *fill_gstate, pdf_gstate *stroke_gstate)
- {
- pdf_run_processor *proc = pdf_new_processor(ctx, sizeof *proc);
- {
- proc->super.usage = usage;
- proc->super.close_processor = pdf_close_run_processor;
- proc->super.drop_processor = pdf_drop_run_processor;
- proc->super.push_resources = pdf_run_push_resources;
- proc->super.pop_resources = pdf_run_pop_resources;
- /* general graphics state */
- proc->super.op_w = pdf_run_w;
- proc->super.op_j = pdf_run_j;
- proc->super.op_J = pdf_run_J;
- proc->super.op_M = pdf_run_M;
- proc->super.op_d = pdf_run_d;
- proc->super.op_ri = pdf_run_ri;
- proc->super.op_i = pdf_run_i;
- proc->super.op_gs_begin = pdf_run_gs_begin;
- proc->super.op_gs_end = pdf_run_gs_end;
- /* transparency graphics state */
- proc->super.op_gs_BM = pdf_run_gs_BM;
- proc->super.op_gs_CA = pdf_run_gs_CA;
- proc->super.op_gs_ca = pdf_run_gs_ca;
- proc->super.op_gs_SMask = pdf_run_gs_SMask;
- /* special graphics state */
- proc->super.op_q = pdf_run_q;
- proc->super.op_Q = pdf_run_Q;
- proc->super.op_cm = pdf_run_cm;
- /* path construction */
- proc->super.op_m = pdf_run_m;
- proc->super.op_l = pdf_run_l;
- proc->super.op_c = pdf_run_c;
- proc->super.op_v = pdf_run_v;
- proc->super.op_y = pdf_run_y;
- proc->super.op_h = pdf_run_h;
- proc->super.op_re = pdf_run_re;
- /* path painting */
- proc->super.op_S = pdf_run_S;
- proc->super.op_s = pdf_run_s;
- proc->super.op_F = pdf_run_F;
- proc->super.op_f = pdf_run_f;
- proc->super.op_fstar = pdf_run_fstar;
- proc->super.op_B = pdf_run_B;
- proc->super.op_Bstar = pdf_run_Bstar;
- proc->super.op_b = pdf_run_b;
- proc->super.op_bstar = pdf_run_bstar;
- proc->super.op_n = pdf_run_n;
- /* clipping paths */
- proc->super.op_W = pdf_run_W;
- proc->super.op_Wstar = pdf_run_Wstar;
- /* text objects */
- proc->super.op_BT = pdf_run_BT;
- proc->super.op_ET = pdf_run_ET;
- /* text state */
- proc->super.op_Tc = pdf_run_Tc;
- proc->super.op_Tw = pdf_run_Tw;
- proc->super.op_Tz = pdf_run_Tz;
- proc->super.op_TL = pdf_run_TL;
- proc->super.op_Tf = pdf_run_Tf;
- proc->super.op_Tr = pdf_run_Tr;
- proc->super.op_Ts = pdf_run_Ts;
- /* text positioning */
- proc->super.op_Td = pdf_run_Td;
- proc->super.op_TD = pdf_run_TD;
- proc->super.op_Tm = pdf_run_Tm;
- proc->super.op_Tstar = pdf_run_Tstar;
- /* text showing */
- proc->super.op_TJ = pdf_run_TJ;
- proc->super.op_Tj = pdf_run_Tj;
- proc->super.op_squote = pdf_run_squote;
- proc->super.op_dquote = pdf_run_dquote;
- /* type 3 fonts */
- proc->super.op_d0 = pdf_run_d0;
- proc->super.op_d1 = pdf_run_d1;
- /* color */
- proc->super.op_CS = pdf_run_CS;
- proc->super.op_cs = pdf_run_cs;
- proc->super.op_SC_color = pdf_run_SC_color;
- proc->super.op_sc_color = pdf_run_sc_color;
- proc->super.op_SC_pattern = pdf_run_SC_pattern;
- proc->super.op_sc_pattern = pdf_run_sc_pattern;
- proc->super.op_SC_shade = pdf_run_SC_shade;
- proc->super.op_sc_shade = pdf_run_sc_shade;
- proc->super.op_G = pdf_run_G;
- proc->super.op_g = pdf_run_g;
- proc->super.op_RG = pdf_run_RG;
- proc->super.op_rg = pdf_run_rg;
- proc->super.op_K = pdf_run_K;
- proc->super.op_k = pdf_run_k;
- /* shadings, images, xobjects */
- proc->super.op_sh = pdf_run_sh;
- if (dev->fill_image || dev->fill_image_mask || dev->clip_image_mask)
- {
- proc->super.op_BI = pdf_run_BI;
- proc->super.op_Do_image = pdf_run_Do_image;
- }
- proc->super.op_Do_form = pdf_run_Do_form;
- /* marked content */
- proc->super.op_MP = pdf_run_MP;
- proc->super.op_DP = pdf_run_DP;
- proc->super.op_BMC = pdf_run_BMC;
- proc->super.op_BDC = pdf_run_BDC;
- proc->super.op_EMC = pdf_run_EMC;
- /* compatibility */
- proc->super.op_BX = pdf_run_BX;
- proc->super.op_EX = pdf_run_EX;
- /* extgstate */
- proc->super.op_gs_OP = pdf_run_gs_OP;
- proc->super.op_gs_op = pdf_run_gs_op;
- proc->super.op_gs_OPM = pdf_run_gs_OPM;
- proc->super.op_gs_UseBlackPtComp = pdf_run_gs_UseBlackPtComp;
- proc->super.op_END = pdf_run_END;
- }
- proc->super.requirements = 0;
- if ((dev->hints & FZ_DONT_DECODE_IMAGES) == 0)
- proc->super.requirements |= PDF_PROCESSOR_REQUIRES_DECODED_IMAGES;
- proc->doc = pdf_keep_document(ctx, doc);
- proc->dev = dev;
- proc->cookie = cookie;
- proc->default_cs = fz_keep_default_colorspaces(ctx, default_cs);
- proc->path = NULL;
- proc->clip = 0;
- proc->clip_even_odd = 0;
- proc->tos.text = NULL;
- proc->tos.tlm = fz_identity;
- proc->tos.tm = fz_identity;
- proc->tos.text_mode = 0;
- proc->gtop = -1;
- proc->marked_content = NULL;
- proc->next_begin_layer = &proc->begin_layer;
- fz_try(ctx)
- {
- proc->path = fz_new_path(ctx);
- proc->gcap = 64;
- proc->gstate = fz_malloc_struct_array(ctx, proc->gcap, pdf_gstate);
- proc->gtop = 0;
- pdf_init_gstate(ctx, &proc->gstate[0], ctm);
- if (fill_gstate)
- {
- pdf_copy_gstate(ctx, &proc->gstate[0], fill_gstate);
- proc->gstate[0].clip_depth = 0;
- proc->gtop++;
- }
- if (stroke_gstate)
- {
- pdf_copy_gstate(ctx, &proc->gstate[proc->gtop], stroke_gstate);
- proc->gstate[proc->gtop].clip_depth = 0;
- proc->gtop++;
- }
- if (gstate)
- {
- pdf_copy_gstate(ctx, &proc->gstate[proc->gtop], gstate);
- proc->gstate[proc->gtop].clip_depth = 0;
- proc->gstate[proc->gtop].ctm = ctm;
- }
- proc->gparent = proc->gtop;
- if (fill_gstate)
- proc->gstate[proc->gtop].fill.gstate_num = 0;
- if (stroke_gstate)
- proc->gstate[proc->gtop].fill.gstate_num = (fill_gstate != NULL);
- /* We need to save an extra level to allow for the parent gstate level. */
- pdf_gsave(ctx, proc);
- /* Structure details */
- {
- pdf_obj *struct_tree_root = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root), PDF_NAME(StructTreeRoot), NULL);
- proc->struct_parent = struct_parent;
- proc->role_map = pdf_keep_obj(ctx, pdf_dict_get(ctx, struct_tree_root, PDF_NAME(RoleMap)));
- /* Annotations and XObjects can be their own content items. We spot this by
- * the struct_parent looking up to be a singular object. */
- if (struct_parent != -1 && struct_tree_root)
- {
- pdf_obj *struct_obj = pdf_lookup_number(ctx, pdf_dict_get(ctx, struct_tree_root, PDF_NAME(ParentTree)), struct_parent);
- if (pdf_is_dict(ctx, struct_obj))
- send_begin_structure(ctx, proc, struct_obj);
- /* We always end structure as required on closedown, so this is safe. */
- }
- }
- }
- fz_catch(ctx)
- {
- pdf_drop_run_processor(ctx, (pdf_processor *) proc);
- fz_free(ctx, proc);
- fz_rethrow(ctx);
- }
- return (pdf_processor*)proc;
- }
|