| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392 |
- // 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 "pdf-annot-imp.h"
- #include <string.h>
- #include <float.h>
- pdf_annot *
- pdf_keep_annot(fz_context *ctx, pdf_annot *annot)
- {
- return fz_keep_imp(ctx, annot, &annot->refs);
- }
- void
- pdf_drop_annot(fz_context *ctx, pdf_annot *annot)
- {
- if (fz_drop_imp(ctx, annot, &annot->refs))
- {
- pdf_drop_obj(ctx, annot->obj);
- fz_free(ctx, annot);
- }
- }
- void
- pdf_drop_annots(fz_context *ctx, pdf_annot *annot)
- {
- while (annot)
- {
- pdf_annot *next = annot->next;
- pdf_drop_annot(ctx, annot);
- annot = next;
- }
- }
- pdf_obj *
- pdf_annot_ap(fz_context *ctx, pdf_annot *annot)
- {
- int flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
- int readonly = flags & PDF_ANNOT_IS_READ_ONLY;
- pdf_obj *ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP));
- pdf_obj *ap_n = pdf_dict_get(ctx, ap, PDF_NAME(N));
- pdf_obj *ap_r = pdf_dict_get(ctx, ap, PDF_NAME(R));
- pdf_obj *ap_d = pdf_dict_get(ctx, ap, PDF_NAME(D));
- if (!readonly && annot->is_hot && annot->is_active && ap_d)
- ap = ap_d;
- else if (!readonly && annot->is_hot && ap_r)
- ap = ap_r;
- else
- ap = ap_n;
- /* AP/N, AP/R and AP/D may be streams, or dictionaries of streams. */
- /* If it's a stream, we have a winner! */
- if (pdf_is_indirect(ctx, ap) && pdf_obj_num_is_stream(ctx, annot->page->doc, pdf_to_num(ctx, ap)))
- return ap;
- /* If it's not a stream, it may be a dictionary containing
- * a range of possible values, that should be indexed by
- * AS. */
- return pdf_dict_get(ctx, ap, pdf_dict_get(ctx, annot->obj, PDF_NAME(AS)));
- }
- int pdf_annot_active(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->is_active : 0;
- }
- void pdf_set_annot_active(fz_context *ctx, pdf_annot *annot, int active)
- {
- int old;
- if (!annot)
- return;
- old = annot->is_active;
- annot->is_active = !!active;
- if (old != annot->is_active)
- pdf_set_annot_has_changed(ctx, annot);
- }
- int pdf_annot_hot(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->is_hot : 0;
- }
- void pdf_set_annot_hot(fz_context *ctx, pdf_annot *annot, int hot)
- {
- int old;
- if (!annot)
- return;
- old = annot->is_hot;
- annot->is_hot = !!hot;
- if (old != annot->is_hot)
- pdf_set_annot_has_changed(ctx, annot);
- }
- fz_matrix
- pdf_annot_transform(fz_context *ctx, pdf_annot *annot)
- {
- fz_rect bbox, rect;
- fz_matrix matrix;
- float w, h, x, y;
- pdf_obj *ap = pdf_annot_ap(ctx, annot);
- rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
- bbox = pdf_xobject_bbox(ctx, ap);
- matrix = pdf_xobject_matrix(ctx, ap);
- bbox = fz_transform_rect(bbox, matrix);
- if (bbox.x1 == bbox.x0)
- w = 0;
- else
- w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0);
- if (bbox.y1 == bbox.y0)
- h = 0;
- else
- h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0);
- x = rect.x0 - (bbox.x0 * w);
- y = rect.y0 - (bbox.y0 * h);
- return fz_pre_scale(fz_translate(x, y), w, h);
- }
- /*
- Internal function for creating a new pdf annotation.
- */
- static pdf_annot *
- pdf_new_annot(fz_context *ctx, pdf_page *page, pdf_obj *obj)
- {
- pdf_annot *annot;
- annot = fz_malloc_struct(ctx, pdf_annot);
- annot->refs = 1;
- annot->page = page; /* only borrowed, as the page owns the annot */
- annot->obj = pdf_keep_obj(ctx, obj);
- return annot;
- }
- void
- pdf_nuke_annots(fz_context *ctx, pdf_page *page)
- {
- pdf_annot *annot;
- for (annot = page->annots; annot; annot = annot->next)
- {
- pdf_drop_obj(ctx, annot->obj);
- annot->obj = NULL;
- pdf_drop_annot(ctx, annot);
- }
- for (annot = page->widgets; annot; annot = annot->next)
- {
- pdf_drop_obj(ctx, annot->obj);
- annot->obj = NULL;
- pdf_drop_annot(ctx, annot);
- }
- page->annots = NULL;
- page->widgets = NULL;
- page->annot_tailp = &page->annots;
- page->widget_tailp = &page->widgets;
- }
- static pdf_annot *find_and_unlink_annot_from_list(fz_context *ctx, pdf_annot **prev, pdf_obj *obj)
- {
- int num = pdf_to_num(ctx, obj);
- pdf_annot *node;
- node = *prev;
- while (node)
- {
- if (pdf_to_num(ctx, node->obj) == num)
- {
- *prev = node->next;
- node->next = NULL;
- return node;
- }
- else
- {
- prev = &node->next;
- node = node->next;
- }
- }
- return NULL;
- }
- void
- pdf_sync_annots(fz_context *ctx, pdf_page *page)
- {
- pdf_annot *old_annots;
- pdf_annot *old_widgets;
- pdf_annot *annot, *next;
- pdf_obj *annots;
- pdf_obj *subtype;
- int i, n;
- // Save list of annots loaded last time (if any).
- old_annots = page->annots;
- old_widgets = page->widgets;
- page->annots = NULL;
- page->widgets = NULL;
- page->annot_tailp = &page->annots;
- page->widget_tailp = &page->widgets;
- // Create new list of annots (reusing old annots when possible)
- annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
- n = pdf_array_len(ctx, annots);
- for (i = 0; i < n; ++i)
- {
- pdf_obj *obj = pdf_array_get(ctx, annots, i);
- if (pdf_is_dict(ctx, obj))
- {
- subtype = pdf_dict_get(ctx, obj, PDF_NAME(Subtype));
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Link)))
- continue;
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Popup)))
- continue;
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget)))
- {
- annot = find_and_unlink_annot_from_list(ctx, &old_widgets, obj);
- if (!annot)
- annot = pdf_new_annot(ctx, page, obj);
- *page->widget_tailp = annot;
- page->widget_tailp = &annot->next;
- }
- else
- {
- annot = find_and_unlink_annot_from_list(ctx, &old_annots, obj);
- if (!annot)
- annot = pdf_new_annot(ctx, page, obj);
- *page->annot_tailp = annot;
- page->annot_tailp = &annot->next;
- }
- }
- }
- // Nuke the annot structs that are no longer used on the page
- for (annot = old_annots; annot; annot = next)
- {
- next = annot->next;
- pdf_drop_obj(ctx, annot->obj);
- annot->obj = NULL;
- pdf_drop_annot(ctx, annot);
- }
- for (annot = old_widgets; annot; annot = next)
- {
- next = annot->next;
- pdf_drop_obj(ctx, annot->obj);
- annot->obj = NULL;
- pdf_drop_annot(ctx, annot);
- }
- }
- void
- pdf_load_annots(fz_context *ctx, pdf_page *page)
- {
- pdf_sync_annots(ctx, page);
- /* We need to run a resynth pass on the annotations on this
- * page. That means rerunning it on the complete document. */
- page->doc->resynth_required = 1;
- /* And actually update the page so that any annotations required
- * get synthesised. */
- pdf_update_page(ctx, page);
- }
- pdf_annot *
- pdf_first_annot(fz_context *ctx, pdf_page *page)
- {
- return page ? page->annots : NULL;
- }
- pdf_annot *
- pdf_next_annot(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->next : NULL;
- }
- pdf_obj *pdf_annot_obj(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->obj : NULL;
- }
- pdf_page *pdf_annot_page(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->page : NULL;
- }
- fz_rect
- pdf_bound_annot(fz_context *ctx, pdf_annot *annot)
- {
- fz_matrix page_ctm;
- fz_rect rect;
- int flags;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
- if (flags & PDF_ANNOT_IS_NO_ROTATE)
- {
- int rotate = pdf_dict_get_inheritable_int(ctx, annot->page->obj, PDF_NAME(Rotate));
- fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm);
- page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y));
- page_ctm = fz_concat(page_ctm, fz_rotate(-rotate));
- page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y));
- }
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return fz_transform_rect(rect, page_ctm);
- }
- void
- pdf_annot_request_resynthesis(fz_context *ctx, pdf_annot *annot)
- {
- if (annot == NULL)
- return;
- annot->needs_new_ap = 1;
- annot->page->doc->resynth_required = 1;
- }
- void
- pdf_annot_request_synthesis(fz_context *ctx, pdf_annot *annot)
- {
- if (annot == NULL)
- return;
- if (!pdf_annot_ap(ctx, annot))
- pdf_annot_request_resynthesis(ctx, annot);
- }
- int
- pdf_annot_needs_resynthesis(fz_context *ctx, pdf_annot *annot)
- {
- return annot ? annot->needs_new_ap : 0;
- }
- void pdf_set_annot_resynthesised(fz_context *ctx, pdf_annot *annot)
- {
- if (annot == NULL)
- return;
- annot->needs_new_ap = 0;
- pdf_set_annot_has_changed(ctx, annot);
- }
- void pdf_set_annot_has_changed(fz_context *ctx, pdf_annot *annot)
- {
- if (annot == NULL)
- return;
- annot->has_new_ap = 1;
- }
- void
- pdf_dirty_annot(fz_context *ctx, pdf_annot *annot)
- {
- pdf_annot_request_resynthesis(ctx, annot);
- }
- const char *
- pdf_string_from_annot_type(fz_context *ctx, enum pdf_annot_type type)
- {
- switch (type)
- {
- case PDF_ANNOT_TEXT: return "Text";
- case PDF_ANNOT_LINK: return "Link";
- case PDF_ANNOT_FREE_TEXT: return "FreeText";
- case PDF_ANNOT_LINE: return "Line";
- case PDF_ANNOT_SQUARE: return "Square";
- case PDF_ANNOT_CIRCLE: return "Circle";
- case PDF_ANNOT_POLYGON: return "Polygon";
- case PDF_ANNOT_POLY_LINE: return "PolyLine";
- case PDF_ANNOT_HIGHLIGHT: return "Highlight";
- case PDF_ANNOT_UNDERLINE: return "Underline";
- case PDF_ANNOT_SQUIGGLY: return "Squiggly";
- case PDF_ANNOT_STRIKE_OUT: return "StrikeOut";
- case PDF_ANNOT_REDACT: return "Redact";
- case PDF_ANNOT_STAMP: return "Stamp";
- case PDF_ANNOT_CARET: return "Caret";
- case PDF_ANNOT_INK: return "Ink";
- case PDF_ANNOT_POPUP: return "Popup";
- case PDF_ANNOT_FILE_ATTACHMENT: return "FileAttachment";
- case PDF_ANNOT_SOUND: return "Sound";
- case PDF_ANNOT_MOVIE: return "Movie";
- case PDF_ANNOT_RICH_MEDIA: return "RichMedia";
- case PDF_ANNOT_WIDGET: return "Widget";
- case PDF_ANNOT_SCREEN: return "Screen";
- case PDF_ANNOT_PRINTER_MARK: return "PrinterMark";
- case PDF_ANNOT_TRAP_NET: return "TrapNet";
- case PDF_ANNOT_WATERMARK: return "Watermark";
- case PDF_ANNOT_3D: return "3D";
- case PDF_ANNOT_PROJECTION: return "Projection";
- default: return "UNKNOWN";
- }
- }
- enum pdf_annot_type
- pdf_annot_type_from_string(fz_context *ctx, const char *subtype)
- {
- if (!strcmp("Text", subtype)) return PDF_ANNOT_TEXT;
- if (!strcmp("Link", subtype)) return PDF_ANNOT_LINK;
- if (!strcmp("FreeText", subtype)) return PDF_ANNOT_FREE_TEXT;
- if (!strcmp("Line", subtype)) return PDF_ANNOT_LINE;
- if (!strcmp("Square", subtype)) return PDF_ANNOT_SQUARE;
- if (!strcmp("Circle", subtype)) return PDF_ANNOT_CIRCLE;
- if (!strcmp("Polygon", subtype)) return PDF_ANNOT_POLYGON;
- if (!strcmp("PolyLine", subtype)) return PDF_ANNOT_POLY_LINE;
- if (!strcmp("Highlight", subtype)) return PDF_ANNOT_HIGHLIGHT;
- if (!strcmp("Underline", subtype)) return PDF_ANNOT_UNDERLINE;
- if (!strcmp("Squiggly", subtype)) return PDF_ANNOT_SQUIGGLY;
- if (!strcmp("StrikeOut", subtype)) return PDF_ANNOT_STRIKE_OUT;
- if (!strcmp("Redact", subtype)) return PDF_ANNOT_REDACT;
- if (!strcmp("Stamp", subtype)) return PDF_ANNOT_STAMP;
- if (!strcmp("Caret", subtype)) return PDF_ANNOT_CARET;
- if (!strcmp("Ink", subtype)) return PDF_ANNOT_INK;
- if (!strcmp("Popup", subtype)) return PDF_ANNOT_POPUP;
- if (!strcmp("FileAttachment", subtype)) return PDF_ANNOT_FILE_ATTACHMENT;
- if (!strcmp("Sound", subtype)) return PDF_ANNOT_SOUND;
- if (!strcmp("Movie", subtype)) return PDF_ANNOT_MOVIE;
- if (!strcmp("RichMedia", subtype)) return PDF_ANNOT_RICH_MEDIA;
- if (!strcmp("Widget", subtype)) return PDF_ANNOT_WIDGET;
- if (!strcmp("Screen", subtype)) return PDF_ANNOT_SCREEN;
- if (!strcmp("PrinterMark", subtype)) return PDF_ANNOT_PRINTER_MARK;
- if (!strcmp("TrapNet", subtype)) return PDF_ANNOT_TRAP_NET;
- if (!strcmp("Watermark", subtype)) return PDF_ANNOT_WATERMARK;
- if (!strcmp("3D", subtype)) return PDF_ANNOT_3D;
- if (!strcmp("Projection", subtype)) return PDF_ANNOT_PROJECTION;
- return PDF_ANNOT_UNKNOWN;
- }
- static void
- begin_annot_op(fz_context *ctx, pdf_annot *annot, const char *op)
- {
- if (!annot->page)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
- pdf_begin_operation(ctx, annot->page->doc, op);
- }
- static void
- end_annot_op(fz_context *ctx, pdf_annot *annot)
- {
- pdf_end_operation(ctx, annot->page->doc);
- }
- static void
- abandon_annot_op(fz_context *ctx, pdf_annot *annot)
- {
- pdf_abandon_operation(ctx, annot->page->doc);
- }
- static int is_allowed_subtype(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
- {
- pdf_obj *subtype;
- subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- while (*allowed) {
- if (pdf_name_eq(ctx, subtype, *allowed))
- return 1;
- allowed++;
- }
- return 0;
- }
- static int is_allowed_subtype_wrap(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- ret = is_allowed_subtype(ctx, annot, property, allowed);
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- static void check_allowed_subtypes(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed)
- {
- pdf_obj *subtype;
- subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- if (!is_allowed_subtype(ctx, annot, property, allowed))
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "%s annotations have no %s property", pdf_to_name(ctx, subtype), pdf_to_name(ctx, property));
- }
- pdf_annot *
- pdf_create_annot_raw(fz_context *ctx, pdf_page *page, enum pdf_annot_type type)
- {
- pdf_annot *annot = NULL;
- pdf_document *doc = page->doc;
- pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0);
- pdf_obj *ind_obj = NULL;
- pdf_obj *free_arr = NULL;
- fz_var(annot);
- fz_var(ind_obj);
- fz_var(free_arr);
- fz_try(ctx)
- {
- int ind_obj_num;
- const char *type_str;
- pdf_obj *annot_arr;
- type_str = pdf_string_from_annot_type(ctx, type);
- if (type == PDF_ANNOT_UNKNOWN)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot create unknown annotation");
- annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
- if (!pdf_is_array(ctx, annot_arr))
- annot_arr = pdf_dict_put_array(ctx, page->obj, PDF_NAME(Annots), 0);
- else if (pdf_is_indirect(ctx, annot_arr))
- {
- free_arr = annot_arr = pdf_copy_array(ctx, annot_arr);
- pdf_dict_put(ctx, page->obj, PDF_NAME(Annots), annot_arr);
- }
- pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot));
- pdf_dict_put_name(ctx, annot_obj, PDF_NAME(Subtype), type_str);
- /*
- Both annotation object and annotation structure are now created.
- Insert the object in the hierarchy and the structure in the
- page's array.
- */
- ind_obj_num = pdf_create_object(ctx, doc);
- pdf_update_object(ctx, doc, ind_obj_num, annot_obj);
- ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0);
- pdf_array_push(ctx, annot_arr, ind_obj);
- annot = pdf_new_annot(ctx, page, ind_obj);
- /*
- Linking must be done after any call that might throw because
- pdf_drop_annots below actually frees a list. Put the new annot
- at the end of the list, so that it will be drawn last.
- */
- if (type == PDF_ANNOT_WIDGET)
- {
- *page->widget_tailp = annot;
- page->widget_tailp = &annot->next;
- }
- else
- {
- *page->annot_tailp = annot;
- page->annot_tailp = &annot->next;
- }
- }
- fz_always(ctx)
- {
- pdf_drop_obj(ctx, free_arr);
- pdf_drop_obj(ctx, annot_obj);
- pdf_drop_obj(ctx, ind_obj);
- }
- fz_catch(ctx)
- {
- pdf_drop_annots(ctx, annot);
- fz_rethrow(ctx);
- }
- return pdf_keep_annot(ctx, annot);
- }
- fz_link *
- pdf_create_link(fz_context *ctx, pdf_page *page, fz_rect bbox, const char *uri)
- {
- fz_link *link = NULL;
- pdf_document *doc = page->doc;
- pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0);
- pdf_obj *ind_obj = NULL;
- pdf_obj *bs = NULL;
- pdf_obj *a = NULL;
- fz_link **linkp;
- fz_rect page_mediabox;
- fz_matrix page_ctm;
- fz_rect rect;
- pdf_obj *free_arr = NULL;
- fz_var(link);
- fz_var(ind_obj);
- fz_var(bs);
- fz_var(a);
- fz_var(free_arr);
- pdf_begin_operation(ctx, page->doc, "Create Link");
- fz_try(ctx)
- {
- int ind_obj_num;
- pdf_obj *annot_arr;
- pdf_page_transform(ctx, page, &page_mediabox, &page_ctm);
- page_ctm = fz_invert_matrix(page_ctm);
- rect = fz_transform_rect(bbox, page_ctm);
- annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
- if (!pdf_is_array(ctx, annot_arr))
- annot_arr = pdf_dict_put_array(ctx, page->obj, PDF_NAME(Annots), 0);
- else if (pdf_is_indirect(ctx, annot_arr))
- {
- free_arr = annot_arr = pdf_copy_array(ctx, annot_arr);
- pdf_dict_put(ctx, page->obj, PDF_NAME(Annots), annot_arr);
- }
- pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot));
- pdf_dict_put(ctx, annot_obj, PDF_NAME(Subtype), PDF_NAME(Link));
- pdf_dict_put_rect(ctx, annot_obj, PDF_NAME(Rect), rect);
- bs = pdf_dict_put_dict(ctx, annot_obj, PDF_NAME(BS), 4);
- pdf_dict_put(ctx, bs, PDF_NAME(S), PDF_NAME(S));
- pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
- pdf_dict_put_int(ctx, bs, PDF_NAME(W), 0);
- pdf_dict_put_drop(ctx, annot_obj, PDF_NAME(A),
- pdf_new_action_from_link(ctx, doc, uri));
- /*
- Both annotation object and annotation structure are now created.
- Insert the object in the hierarchy and the structure in the
- page's array.
- */
- ind_obj_num = pdf_create_object(ctx, doc);
- pdf_update_object(ctx, doc, ind_obj_num, annot_obj);
- ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0);
- pdf_array_push(ctx, annot_arr, ind_obj);
- link = (fz_link *) pdf_new_link(ctx, page, bbox, uri, annot_obj);
- linkp = &page->links;
- while (*linkp != NULL)
- linkp = &(*linkp)->next;
- *linkp = link;
- pdf_end_operation(ctx, page->doc);
- }
- fz_always(ctx)
- {
- pdf_drop_obj(ctx, free_arr);
- pdf_drop_obj(ctx, annot_obj);
- pdf_drop_obj(ctx, ind_obj);
- }
- fz_catch(ctx)
- {
- pdf_abandon_operation(ctx, page->doc);
- fz_rethrow(ctx);
- }
- return fz_keep_link(ctx, link);
- }
- void pdf_delete_link(fz_context *ctx, pdf_page *page, fz_link *link)
- {
- fz_link **linkptr;
- pdf_obj *annots;
- int i;
- if (link == NULL || page == NULL || page != ((pdf_link *) link)->page)
- return;
- for (linkptr = &page->links; *linkptr; linkptr = &((*linkptr)->next))
- {
- if (*linkptr == link)
- break;
- }
- if (*linkptr == NULL)
- return;
- /* Link may no longer borrow page pointer, since they are separated */
- ((pdf_link *) link)->page = NULL;
- pdf_begin_operation(ctx, page->doc, "Delete Link");
- fz_try(ctx)
- {
- annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
- i = pdf_array_find(ctx, annots, ((pdf_link *) link)->obj);
- if (i >= 0)
- pdf_array_delete(ctx, annots, i);
- *linkptr = link->next;
- link->next = NULL;
- fz_drop_link(ctx, link);
- pdf_end_operation(ctx, page->doc);
- }
- fz_catch(ctx)
- {
- pdf_abandon_operation(ctx, page->doc);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *
- pdf_add_popup_annot(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *annots, *popup;
- popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- if (popup)
- return popup;
- annots = pdf_dict_get(ctx, annot->page->obj, PDF_NAME(Annots));
- if (!annots)
- return NULL;
- popup = pdf_add_new_dict(ctx, annot->page->doc, 4);
- pdf_array_push_drop(ctx, annots, popup);
- pdf_dict_put(ctx, popup, PDF_NAME(Type), PDF_NAME(Annot));
- pdf_dict_put(ctx, popup, PDF_NAME(Subtype), PDF_NAME(Popup));
- pdf_dict_put(ctx, popup, PDF_NAME(Parent), annot->obj);
- pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), fz_make_rect(0,0,0,0));
- pdf_dict_put(ctx, annot->obj, PDF_NAME(Popup), popup);
- return popup;
- }
- static pdf_obj *popup_subtypes[] = {
- PDF_NAME(Text),
- PDF_NAME(FreeText),
- PDF_NAME(Line),
- PDF_NAME(Square),
- PDF_NAME(Circle),
- PDF_NAME(Polygon),
- PDF_NAME(PolyLine),
- PDF_NAME(Highlight),
- PDF_NAME(Underline),
- PDF_NAME(Squiggly),
- PDF_NAME(StrikeOut),
- PDF_NAME(Stamp),
- PDF_NAME(Caret),
- PDF_NAME(Ink),
- PDF_NAME(FileAttachment),
- PDF_NAME(Sound),
- PDF_NAME(Redact),
- NULL,
- };
- int
- pdf_annot_has_popup(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Popup), popup_subtypes);
- }
- void pdf_set_annot_popup(fz_context *ctx, pdf_annot *annot, fz_rect rect)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *popup;
- begin_annot_op(ctx, annot, "Set popup");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Popup), popup_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- rect = fz_transform_rect(rect, inv_page_ctm);
- popup = pdf_add_popup_annot(ctx, annot);
- pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), rect);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- fz_rect pdf_annot_popup(fz_context *ctx, pdf_annot *annot)
- {
- fz_matrix page_ctm;
- fz_rect rect;
- pdf_obj *popup;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Popup), popup_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- rect = pdf_dict_get_rect(ctx, popup, PDF_NAME(Rect));
- rect = fz_transform_rect(rect, page_ctm);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return rect;
- }
- pdf_annot *
- pdf_create_annot(fz_context *ctx, pdf_page *page, enum pdf_annot_type type)
- {
- static const float black[3] = { 0, 0, 0 };
- static const float red[3] = { 1, 0, 0 };
- static const float green[3] = { 0, 1, 0 };
- static const float blue[3] = { 0, 0, 1 };
- static const float yellow[3] = { 1, 1, 0 };
- static const float magenta[3] = { 1, 0, 1 };
- int flags = PDF_ANNOT_IS_PRINT; /* Make printable as default */
- pdf_annot *annot = NULL;
- fz_var(annot);
- pdf_begin_operation(ctx, page->doc, "Create Annotation");
- fz_try(ctx)
- {
- annot = pdf_create_annot_raw(ctx, page, type);
- switch (type)
- {
- default:
- break;
- case PDF_ANNOT_TEXT:
- case PDF_ANNOT_FILE_ATTACHMENT:
- case PDF_ANNOT_SOUND:
- {
- fz_rect icon_rect = { 12, 12, 12+20, 12+20 };
- flags = PDF_ANNOT_IS_PRINT | PDF_ANNOT_IS_NO_ZOOM | PDF_ANNOT_IS_NO_ROTATE;
- pdf_set_annot_rect(ctx, annot, icon_rect);
- pdf_set_annot_color(ctx, annot, 3, yellow);
- pdf_set_annot_popup(ctx, annot, fz_make_rect(32, 12, 32+200, 12+100));
- }
- break;
- case PDF_ANNOT_FREE_TEXT:
- {
- fz_rect text_rect = { 12, 12, 12+200, 12+100 };
- /* Use undocumented Adobe property to match page rotation. */
- int rot = pdf_dict_get_inheritable_int(ctx, page->obj, PDF_NAME(Rotate));
- if (rot != 0)
- pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Rotate), rot);
- pdf_set_annot_rect(ctx, annot, text_rect);
- pdf_set_annot_border_width(ctx, annot, 0);
- pdf_set_annot_default_appearance(ctx, annot, "Helv", 12, nelem(black), black);
- }
- break;
- case PDF_ANNOT_STAMP:
- {
- fz_rect stamp_rect = { 12, 12, 12+190, 12+50 };
- pdf_set_annot_rect(ctx, annot, stamp_rect);
- pdf_set_annot_color(ctx, annot, 3, red);
- pdf_set_annot_icon_name(ctx, annot, "Draft");
- }
- break;
- case PDF_ANNOT_CARET:
- {
- fz_rect caret_rect = { 12, 12, 12+18, 12+15 };
- pdf_set_annot_rect(ctx, annot, caret_rect);
- pdf_set_annot_color(ctx, annot, 3, blue);
- }
- break;
- case PDF_ANNOT_LINE:
- {
- fz_point a = { 12, 12 }, b = { 12 + 100, 12 + 50 };
- pdf_set_annot_line(ctx, annot, a, b);
- pdf_set_annot_border_width(ctx, annot, 1);
- pdf_set_annot_color(ctx, annot, 3, red);
- }
- break;
- case PDF_ANNOT_SQUARE:
- case PDF_ANNOT_CIRCLE:
- {
- fz_rect shape_rect = { 12, 12, 12+100, 12+50 };
- fz_rect rd = { 0.5, 0.5, 0.5, 0.5 };
- pdf_set_annot_rect(ctx, annot, shape_rect);
- pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd);
- pdf_set_annot_border_width(ctx, annot, 1);
- pdf_set_annot_color(ctx, annot, 3, red);
- }
- break;
- case PDF_ANNOT_POLYGON:
- case PDF_ANNOT_POLY_LINE:
- case PDF_ANNOT_INK:
- {
- fz_rect rd = { 0.5, 0.5, 0.5, 0.5 };
- pdf_set_annot_border_width(ctx, annot, 1);
- pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd);
- pdf_set_annot_color(ctx, annot, 3, red);
- }
- break;
- case PDF_ANNOT_HIGHLIGHT:
- pdf_set_annot_color(ctx, annot, 3, yellow);
- break;
- case PDF_ANNOT_UNDERLINE:
- pdf_set_annot_color(ctx, annot, 3, green);
- break;
- case PDF_ANNOT_STRIKE_OUT:
- pdf_set_annot_color(ctx, annot, 3, red);
- break;
- case PDF_ANNOT_SQUIGGLY:
- pdf_set_annot_color(ctx, annot, 3, magenta);
- break;
- }
- pdf_dict_put(ctx, annot->obj, PDF_NAME(P), page->obj);
- pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags);
- pdf_end_operation(ctx, page->doc);
- }
- fz_catch(ctx)
- {
- pdf_drop_annot(ctx, annot);
- pdf_abandon_operation(ctx, page->doc);
- fz_rethrow(ctx);
- }
- return annot;
- }
- static int
- remove_from_tree(fz_context *ctx, pdf_obj *arr, pdf_obj *item, pdf_cycle_list *cycle_up)
- {
- pdf_cycle_list cycle;
- int i, n, res = 0;
- if (arr == NULL || pdf_cycle(ctx, &cycle, cycle_up, arr))
- return 0;
- n = pdf_array_len(ctx, arr);
- for (i = 0; i < n; ++i)
- {
- pdf_obj *obj = pdf_array_get(ctx, arr, i);
- if (!pdf_objcmp(ctx, obj, item))
- {
- pdf_array_delete(ctx, arr, i);
- res = 1;
- break;
- }
- if (remove_from_tree(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Kids)), item, &cycle))
- {
- res = 1;
- break;
- }
- }
- return res;
- }
- void
- pdf_delete_annot(fz_context *ctx, pdf_page *page, pdf_annot *annot)
- {
- pdf_document *doc;
- pdf_annot **annotptr;
- pdf_obj *annot_arr, *popup;
- int i;
- int is_widget = 0;
- if (annot == NULL || page == NULL || page != annot->page)
- return;
- doc = page->doc;
- /* Look for the annot in the page's list */
- for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next)
- {
- if (*annotptr == annot)
- break;
- }
- if (*annotptr == NULL)
- {
- is_widget = 1;
- /* Look also in the widget list*/
- for (annotptr = &page->widgets; *annotptr; annotptr = &(*annotptr)->next)
- {
- if (*annotptr == annot)
- break;
- }
- }
- /* Check the passed annotation was of this page */
- if (*annotptr == NULL)
- return;
- pdf_begin_operation(ctx, page->doc, "Delete Annotation");
- /* Remove annot from page's list */
- *annotptr = annot->next;
- /* Annot may no longer borrow page pointer, since they are separated */
- annot->page = NULL;
- /* If the removed annotation was the last in the list adjust the end pointer */
- if (*annotptr == NULL)
- {
- if (is_widget)
- page->widget_tailp = annotptr;
- else
- page->annot_tailp = annotptr;
- }
- fz_try(ctx)
- {
- /* Remove the annot from the "Annots" array. */
- annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
- i = pdf_array_find(ctx, annot_arr, annot->obj);
- if (i >= 0)
- pdf_array_delete(ctx, annot_arr, i);
- /* Remove the associated Popup annotation from the Annots array */
- popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- if (popup)
- {
- i = pdf_array_find(ctx, annot_arr, popup);
- if (i >= 0)
- pdf_array_delete(ctx, annot_arr, i);
- }
- /* For a widget, remove also from the AcroForm tree */
- if (is_widget)
- {
- pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
- pdf_obj *acroform = pdf_dict_get(ctx, root, PDF_NAME(AcroForm));
- pdf_obj *fields = pdf_dict_get(ctx, acroform, PDF_NAME(Fields));
- (void)remove_from_tree(ctx, fields, annot->obj, NULL);
- }
- /* The garbage collection pass when saving will remove the annot object,
- * removing it here may break files if multiple pages use the same annot. */
- pdf_end_operation(ctx, page->doc);
- }
- fz_always(ctx)
- {
- /* Drop the reference to annot previously held by the page list. */
- pdf_drop_annot(ctx, annot);
- }
- fz_catch(ctx)
- {
- pdf_abandon_operation(ctx, page->doc);
- fz_rethrow(ctx);
- }
- }
- enum pdf_annot_type
- pdf_annot_type(fz_context *ctx, pdf_annot *annot)
- {
- enum pdf_annot_type ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- const char *subtype = pdf_dict_get_name(ctx, annot->obj, PDF_NAME(Subtype));
- ret = pdf_annot_type_from_string(ctx, subtype);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- int
- pdf_annot_flags(fz_context *ctx, pdf_annot *annot)
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- ret = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F));
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_flags(fz_context *ctx, pdf_annot *annot, int flags)
- {
- begin_annot_op(ctx, annot, "Set flags");
- fz_try(ctx)
- {
- pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- static pdf_obj *rect_subtypes[] = {
- PDF_NAME(Text),
- PDF_NAME(FreeText),
- PDF_NAME(Square),
- PDF_NAME(Circle),
- PDF_NAME(Redact),
- PDF_NAME(Stamp),
- PDF_NAME(Caret),
- PDF_NAME(Popup),
- PDF_NAME(FileAttachment),
- PDF_NAME(Sound),
- PDF_NAME(Movie),
- PDF_NAME(Widget),
- NULL,
- };
- int
- pdf_annot_has_rect(fz_context *ctx, pdf_annot *annot)
- {
- /* True for annotations where the user can manipulate the size or location
- * of the annotation through the Rect.
- * False for annotations where the Rect is computed from other
- * annotation data such as InkList, QuadPoints, and Vertices.
- */
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Rect), rect_subtypes);
- }
- fz_rect
- pdf_annot_rect(fz_context *ctx, pdf_annot *annot)
- {
- fz_matrix page_ctm;
- fz_rect rect;
- fz_rect rd;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
- /* remove RD adjustment from bounding box to get design box */
- rd = pdf_annot_rect_diff(ctx, annot);
- rect.x0 += rd.x0;
- rect.x1 -= rd.x1;
- rect.y0 += rd.y0;
- rect.y1 -= rd.y1;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return fz_transform_rect(rect, page_ctm);
- }
- void
- pdf_set_annot_rect(fz_context *ctx, pdf_annot *annot, fz_rect rect)
- {
- fz_matrix page_ctm, inv_page_ctm;
- fz_rect rd;
- begin_annot_op(ctx, annot, "Set rectangle");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- rect = fz_transform_rect(rect, inv_page_ctm);
- /* add RD adjustment to design box to get bounding box */
- rd = pdf_annot_rect_diff(ctx, annot);
- rect.x0 -= rd.x0;
- rect.x1 += rd.x1;
- rect.y0 -= rd.y0;
- rect.y1 += rd.y1;
- pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), rect);
- /* recalculate callout line as necessary */
- if (pdf_annot_has_callout(ctx, annot))
- {
- pdf_set_annot_callout_point(ctx, annot, pdf_annot_callout_point(ctx, annot));
- }
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- const char *
- pdf_annot_contents(fz_context *ctx, pdf_annot *annot)
- {
- return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(Contents));
- }
- void
- pdf_set_annot_contents(fz_context *ctx, pdf_annot *annot, const char *text)
- {
- begin_annot_op(ctx, annot, "Set contents");
- fz_try(ctx)
- {
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Contents), text);
- pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *markup_subtypes[] = {
- PDF_NAME(Text),
- PDF_NAME(FreeText),
- PDF_NAME(Line),
- PDF_NAME(Square),
- PDF_NAME(Circle),
- PDF_NAME(Polygon),
- PDF_NAME(PolyLine),
- PDF_NAME(Highlight),
- PDF_NAME(Underline),
- PDF_NAME(Squiggly),
- PDF_NAME(StrikeOut),
- PDF_NAME(Redact),
- PDF_NAME(Stamp),
- PDF_NAME(Caret),
- PDF_NAME(Ink),
- PDF_NAME(FileAttachment),
- PDF_NAME(Sound),
- NULL,
- };
- int
- pdf_annot_has_rich_contents(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(RC), markup_subtypes);
- }
- const char *
- pdf_annot_rich_contents(fz_context *ctx, pdf_annot *annot)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(RC), markup_subtypes);
- return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(RC));
- }
- void
- pdf_set_annot_rich_contents(fz_context *ctx, pdf_annot *annot, const char *plain, const char *rich)
- {
- begin_annot_op(ctx, annot, "Set rich contents");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(RC), markup_subtypes);
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Contents), plain);
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(RC), rich);
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *default_style_subtypes[] = {
- PDF_NAME(FreeText),
- PDF_NAME(Widget),
- NULL,
- };
- int
- pdf_annot_has_rich_defaults(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(DS), default_style_subtypes);
- }
- const char *
- pdf_annot_rich_defaults(fz_context *ctx, pdf_annot *annot)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(DS), default_style_subtypes);
- return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(DS));
- }
- void
- pdf_set_annot_rich_defaults(fz_context *ctx, pdf_annot *annot, const char *style)
- {
- begin_annot_op(ctx, annot, "Set rich defaults");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(DS), default_style_subtypes);
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(DS), style);
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- int
- pdf_annot_has_open(fz_context *ctx, pdf_annot *annot)
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- ret = (subtype == PDF_NAME(Text) || popup);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- int
- pdf_annot_is_open(fz_context *ctx, pdf_annot *annot)
- {
- int ret = 0;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- if (popup)
- ret = pdf_dict_get_bool(ctx, popup, PDF_NAME(Open));
- else if (subtype == PDF_NAME(Text))
- ret = pdf_dict_get_bool(ctx, annot->obj, PDF_NAME(Open));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_is_open(fz_context *ctx, pdf_annot *annot, int is_open)
- {
- begin_annot_op(ctx, annot, is_open ? "Open" : "Close");
- fz_try(ctx)
- {
- pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup));
- if (popup)
- {
- pdf_dict_put_bool(ctx, popup, PDF_NAME(Open), is_open);
- pdf_dirty_annot(ctx, annot);
- }
- else if (subtype == PDF_NAME(Text))
- {
- pdf_dict_put_bool(ctx, annot->obj, PDF_NAME(Open), is_open);
- pdf_dirty_annot(ctx, annot);
- }
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *icon_name_subtypes[] = {
- PDF_NAME(FileAttachment),
- PDF_NAME(Sound),
- PDF_NAME(Stamp),
- PDF_NAME(Text),
- NULL,
- };
- int
- pdf_annot_has_icon_name(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
- }
- const char *
- pdf_annot_icon_name(fz_context *ctx, pdf_annot *annot)
- {
- const char *ret;
- pdf_obj *name;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
- name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name));
- if (!name)
- {
- pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Text)))
- {
- ret = "Note";
- break;
- }
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Stamp)))
- {
- ret = ""; // Should be "Draft" according to spec
- break;
- }
- if (pdf_name_eq(ctx, subtype, PDF_NAME(FileAttachment)))
- {
- ret = "PushPin";
- break;
- }
- if (pdf_name_eq(ctx, subtype, PDF_NAME(Sound)))
- {
- ret = "Speaker";
- break;
- }
- }
- ret = pdf_to_name(ctx, name);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_icon_name(fz_context *ctx, pdf_annot *annot, const char *name)
- {
- begin_annot_op(ctx, annot, "Set icon name");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes);
- if (name)
- pdf_dict_put_name(ctx, annot->obj, PDF_NAME(Name), name);
- else
- pdf_dict_del(ctx, annot->obj, PDF_NAME(Name));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- int
- pdf_annot_is_standard_stamp(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name));
- if (pdf_name_eq(ctx, name, PDF_NAME(Approved))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(AsIs))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Confidential))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Departmental))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Draft))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Experimental))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Expired))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Final))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(ForComment))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(ForPublicRelease))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(NotApproved))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(NotForPublicRelease))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(Sold))) return 1;
- else if (pdf_name_eq(ctx, name, PDF_NAME(TopSecret))) return 1;
- else if (pdf_annot_stamp_image_obj(ctx, annot) != NULL) return 1;
- else return 0;
- }
- enum pdf_line_ending pdf_line_ending_from_name(fz_context *ctx, pdf_obj *end)
- {
- if (pdf_name_eq(ctx, end, PDF_NAME(None))) return PDF_ANNOT_LE_NONE;
- else if (pdf_name_eq(ctx, end, PDF_NAME(Square))) return PDF_ANNOT_LE_SQUARE;
- else if (pdf_name_eq(ctx, end, PDF_NAME(Circle))) return PDF_ANNOT_LE_CIRCLE;
- else if (pdf_name_eq(ctx, end, PDF_NAME(Diamond))) return PDF_ANNOT_LE_DIAMOND;
- else if (pdf_name_eq(ctx, end, PDF_NAME(OpenArrow))) return PDF_ANNOT_LE_OPEN_ARROW;
- else if (pdf_name_eq(ctx, end, PDF_NAME(ClosedArrow))) return PDF_ANNOT_LE_CLOSED_ARROW;
- else if (pdf_name_eq(ctx, end, PDF_NAME(Butt))) return PDF_ANNOT_LE_BUTT;
- else if (pdf_name_eq(ctx, end, PDF_NAME(ROpenArrow))) return PDF_ANNOT_LE_R_OPEN_ARROW;
- else if (pdf_name_eq(ctx, end, PDF_NAME(RClosedArrow))) return PDF_ANNOT_LE_R_CLOSED_ARROW;
- else if (pdf_name_eq(ctx, end, PDF_NAME(Slash))) return PDF_ANNOT_LE_SLASH;
- else return PDF_ANNOT_LE_NONE;
- }
- enum pdf_line_ending pdf_line_ending_from_string(fz_context *ctx, const char *end)
- {
- if (!strcmp(end, "None")) return PDF_ANNOT_LE_NONE;
- else if (!strcmp(end, "Square")) return PDF_ANNOT_LE_SQUARE;
- else if (!strcmp(end, "Circle")) return PDF_ANNOT_LE_CIRCLE;
- else if (!strcmp(end, "Diamond")) return PDF_ANNOT_LE_DIAMOND;
- else if (!strcmp(end, "OpenArrow")) return PDF_ANNOT_LE_OPEN_ARROW;
- else if (!strcmp(end, "ClosedArrow")) return PDF_ANNOT_LE_CLOSED_ARROW;
- else if (!strcmp(end, "Butt")) return PDF_ANNOT_LE_BUTT;
- else if (!strcmp(end, "ROpenArrow")) return PDF_ANNOT_LE_R_OPEN_ARROW;
- else if (!strcmp(end, "RClosedArrow")) return PDF_ANNOT_LE_R_CLOSED_ARROW;
- else if (!strcmp(end, "Slash")) return PDF_ANNOT_LE_SLASH;
- else return PDF_ANNOT_LE_NONE;
- }
- pdf_obj *pdf_name_from_line_ending(fz_context *ctx, enum pdf_line_ending end)
- {
- switch (end)
- {
- default:
- case PDF_ANNOT_LE_NONE: return PDF_NAME(None);
- case PDF_ANNOT_LE_SQUARE: return PDF_NAME(Square);
- case PDF_ANNOT_LE_CIRCLE: return PDF_NAME(Circle);
- case PDF_ANNOT_LE_DIAMOND: return PDF_NAME(Diamond);
- case PDF_ANNOT_LE_OPEN_ARROW: return PDF_NAME(OpenArrow);
- case PDF_ANNOT_LE_CLOSED_ARROW: return PDF_NAME(ClosedArrow);
- case PDF_ANNOT_LE_BUTT: return PDF_NAME(Butt);
- case PDF_ANNOT_LE_R_OPEN_ARROW: return PDF_NAME(ROpenArrow);
- case PDF_ANNOT_LE_R_CLOSED_ARROW: return PDF_NAME(RClosedArrow);
- case PDF_ANNOT_LE_SLASH: return PDF_NAME(Slash);
- }
- }
- const char *pdf_string_from_line_ending(fz_context *ctx, enum pdf_line_ending end)
- {
- switch (end)
- {
- default:
- case PDF_ANNOT_LE_NONE: return "None";
- case PDF_ANNOT_LE_SQUARE: return "Square";
- case PDF_ANNOT_LE_CIRCLE: return "Circle";
- case PDF_ANNOT_LE_DIAMOND: return "Diamond";
- case PDF_ANNOT_LE_OPEN_ARROW: return "OpenArrow";
- case PDF_ANNOT_LE_CLOSED_ARROW: return "ClosedArrow";
- case PDF_ANNOT_LE_BUTT: return "Butt";
- case PDF_ANNOT_LE_R_OPEN_ARROW: return "ROpenArrow";
- case PDF_ANNOT_LE_R_CLOSED_ARROW: return "RClosedArrow";
- case PDF_ANNOT_LE_SLASH: return "Slash";
- }
- }
- static pdf_obj *line_ending_subtypes[] = {
- PDF_NAME(FreeText),
- PDF_NAME(Line),
- PDF_NAME(PolyLine),
- PDF_NAME(Polygon),
- NULL,
- };
- int
- pdf_annot_has_line_ending_styles(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
- }
- void
- pdf_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot,
- enum pdf_line_ending *start_style,
- enum pdf_line_ending *end_style)
- {
- pdf_obj *style;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
- style = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
- *start_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 0));
- *end_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 1));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- enum pdf_line_ending
- pdf_annot_line_start_style(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
- return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 0));
- }
- enum pdf_line_ending
- pdf_annot_line_end_style(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
- return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 1));
- }
- void
- pdf_set_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot,
- enum pdf_line_ending start_style,
- enum pdf_line_ending end_style)
- {
- pdf_obj *style;
- begin_annot_op(ctx, annot, "Set line endings");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes);
- style = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(LE), 2);
- pdf_array_put_drop(ctx, style, 0, pdf_name_from_line_ending(ctx, start_style));
- pdf_array_put_drop(ctx, style, 1, pdf_name_from_line_ending(ctx, end_style));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_line_start_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending s)
- {
- enum pdf_line_ending e = pdf_annot_line_end_style(ctx, annot);
- pdf_set_annot_line_ending_styles(ctx, annot, s, e);
- }
- void
- pdf_set_annot_line_end_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending e)
- {
- enum pdf_line_ending s = pdf_annot_line_start_style(ctx, annot);
- pdf_set_annot_line_ending_styles(ctx, annot, s, e);
- }
- static pdf_obj *border_style_subtypes[] = {
- PDF_NAME(Circle),
- PDF_NAME(FreeText),
- PDF_NAME(Ink),
- PDF_NAME(Line),
- PDF_NAME(Polygon),
- PDF_NAME(PolyLine),
- PDF_NAME(Square),
- PDF_NAME(Widget),
- NULL,
- };
- static pdf_obj *border_effect_subtypes[] = {
- PDF_NAME(Circle),
- PDF_NAME(FreeText),
- PDF_NAME(Polygon),
- PDF_NAME(Square),
- NULL,
- };
- int
- pdf_annot_has_border(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- }
- int
- pdf_annot_has_border_effect(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
- }
- enum pdf_border_style
- pdf_annot_border_style(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *bs, *s;
- enum pdf_border_style style;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- s = pdf_dict_get(ctx, bs, PDF_NAME(S));
- if (s == PDF_NAME(D))
- style = PDF_BORDER_STYLE_DASHED;
- else if (s == PDF_NAME(B))
- style = PDF_BORDER_STYLE_BEVELED;
- else if (s == PDF_NAME(I))
- style = PDF_BORDER_STYLE_INSET;
- else if (s == PDF_NAME(U))
- style = PDF_BORDER_STYLE_UNDERLINE;
- else
- style = PDF_BORDER_STYLE_SOLID;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return style;
- }
- float
- pdf_annot_border_width(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *bs, *bs_w, *border;
- float ret = 1;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- bs_w = pdf_dict_get(ctx, bs, PDF_NAME(W));
- if (pdf_is_number(ctx, bs_w))
- {
- ret = pdf_to_real(ctx, bs_w);
- break;
- }
- border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
- bs_w = pdf_array_get(ctx, border, 2);
- if (pdf_is_number(ctx, bs_w))
- ret = pdf_to_real(ctx, bs_w);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- float
- pdf_annot_border(fz_context *ctx, pdf_annot *annot)
- {
- /* DEPRECATED */
- return pdf_annot_border_width(ctx, annot);
- }
- int
- pdf_annot_border_dash_count(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *bs, *d, *border;
- int count;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- d = pdf_dict_get(ctx, bs, PDF_NAME(D));
- /* Query legacy dash pattern as a fallback */
- border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
- if (!pdf_is_array(ctx, d) && pdf_is_array(ctx, border))
- d = pdf_array_get(ctx, border, 3);
- count = pdf_array_len(ctx, d);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return count;
- }
- float
- pdf_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, int i)
- {
- pdf_obj *bs, *d, *border;
- float length;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- d = pdf_dict_get(ctx, bs, PDF_NAME(D));
- /* Query legacy dash pattern as a fallback */
- border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
- if (!pdf_is_array(ctx, d) && pdf_is_array(ctx, border))
- d = pdf_array_get(ctx, border, 3);
- length = pdf_array_get_real(ctx, d, i);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return length;
- }
- enum pdf_border_effect
- pdf_annot_border_effect(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *be;
- enum pdf_border_effect effect;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
- be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
- if (pdf_dict_get(ctx, be, PDF_NAME(S)) == PDF_NAME(C))
- effect = PDF_BORDER_EFFECT_CLOUDY;
- else
- effect = PDF_BORDER_EFFECT_NONE;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return effect;
- }
- float
- pdf_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *be;
- float intensity;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
- be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
- intensity = pdf_dict_get_real(ctx, be, PDF_NAME(I));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return intensity;
- }
- void
- pdf_set_annot_border_width(fz_context *ctx, pdf_annot *annot, float width)
- {
- pdf_obj *bs;
- pdf_obj *type;
- float old_width, adj;
- pdf_obj *rectobj;
- begin_annot_op(ctx, annot, "Set border width");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- if (!pdf_is_dict(ctx, bs))
- bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
- pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
- old_width = pdf_dict_get_real(ctx, bs, PDF_NAME(W));
- pdf_dict_put_real(ctx, bs, PDF_NAME(W), width);
- rectobj = pdf_dict_get(ctx, annot->obj, PDF_NAME(Rect));
- if (pdf_is_array(ctx, rectobj)) {
- fz_rect rect = pdf_to_rect(ctx, rectobj);
- adj = (width - old_width)/2;
- rect.x0 -= adj;
- rect.x1 += adj;
- rect.y0 -= adj;
- rect.y1 += adj;
- pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), rect);
- /* For any of these types, we want to adjust the Rect and RD
- * together so that Rect+RD doesn't change, but the border stroke
- * stays centred on the same point. */
- type = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype));
- if (pdf_name_eq(ctx, type, PDF_NAME(Square)) ||
- pdf_name_eq(ctx, type, PDF_NAME(Circle)))
- {
- fz_rect rd = pdf_annot_rect_diff(ctx, annot);
- rd.x0 += adj;
- rd.x1 += adj;
- rd.y0 += adj;
- rd.y1 += adj;
- pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd);
- }
- }
- pdf_dict_del(ctx, annot->obj, PDF_NAME(Border)); /* deprecated */
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_border(fz_context *ctx, pdf_annot *annot, float w)
- {
- /* DEPRECATED */
- pdf_set_annot_border_width(ctx, annot, w);
- }
- void
- pdf_set_annot_border_style(fz_context *ctx, pdf_annot *annot, enum pdf_border_style style)
- {
- pdf_obj *bs, *s;
- begin_annot_op(ctx, annot, "Set border style");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- if (!pdf_is_dict(ctx, bs))
- bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
- pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border));
- switch (style)
- {
- default:
- case PDF_BORDER_STYLE_SOLID: s = PDF_NAME(S); break;
- case PDF_BORDER_STYLE_DASHED: s = PDF_NAME(D); break;
- case PDF_BORDER_STYLE_BEVELED: s = PDF_NAME(B); break;
- case PDF_BORDER_STYLE_INSET: s = PDF_NAME(I); break;
- case PDF_BORDER_STYLE_UNDERLINE: s = PDF_NAME(U); break;
- }
- pdf_dict_put(ctx, bs, PDF_NAME(S), s);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_clear_annot_border_dash(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *bs, *border;
- begin_annot_op(ctx, annot, "Clear border dash pattern");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- if (!pdf_is_dict(ctx, bs))
- bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
- pdf_dict_del(ctx, bs, PDF_NAME(D));
- /* Remove legacy dash pattern */
- border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
- if (pdf_is_array(ctx, border))
- pdf_array_delete(ctx, border, 3);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_add_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, float length)
- {
- pdf_obj *bs, *d, *border;
- begin_annot_op(ctx, annot, "Add border dash pattern item");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes);
- bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS));
- if (!pdf_is_dict(ctx, bs))
- bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1);
- d = pdf_dict_get(ctx, bs, PDF_NAME(D));
- if (!pdf_is_array(ctx, d))
- d = pdf_dict_put_array(ctx, bs, PDF_NAME(D), 1);
- pdf_array_push_real(ctx, d, length);
- /* Remove legacy dash pattern */
- border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border));
- if (pdf_is_array(ctx, border))
- pdf_array_delete(ctx, border, 3);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_border_effect(fz_context *ctx, pdf_annot *annot, enum pdf_border_effect effect)
- {
- pdf_obj *be, *s;
- begin_annot_op(ctx, annot, "Set border effect");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
- be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
- if (!pdf_is_dict(ctx, be))
- be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1);
- switch (effect)
- {
- default:
- case PDF_BORDER_EFFECT_NONE: s = PDF_NAME(S); break;
- case PDF_BORDER_EFFECT_CLOUDY: s = PDF_NAME(C); break;
- }
- pdf_dict_put(ctx, be, PDF_NAME(S), s);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot, float intensity)
- {
- pdf_obj *be;
- begin_annot_op(ctx, annot, "Set border effect intensity");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes);
- be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE));
- if (!pdf_is_dict(ctx, be))
- be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1);
- pdf_dict_put_real(ctx, be, PDF_NAME(I), intensity);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- fz_text_language
- pdf_document_language(fz_context *ctx, pdf_document *doc)
- {
- pdf_obj *trailer = pdf_trailer(ctx, doc);
- pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root));
- pdf_obj *lang = pdf_dict_get(ctx, root, PDF_NAME(Lang));
- return fz_text_language_from_string(pdf_to_text_string(ctx, lang));
- }
- void pdf_set_document_language(fz_context *ctx, pdf_document *doc, fz_text_language lang)
- {
- pdf_obj *trailer = pdf_trailer(ctx, doc);
- pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root));
- char buf[8];
- if (lang == FZ_LANG_UNSET)
- pdf_dict_del(ctx, root, PDF_NAME(Lang));
- else
- pdf_dict_put_text_string(ctx, root, PDF_NAME(Lang), fz_string_from_text_language(buf, lang));
- }
- fz_text_language
- pdf_annot_language(fz_context *ctx, pdf_annot *annot)
- {
- fz_text_language ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *lang = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(Lang));
- if (lang)
- ret = fz_text_language_from_string(pdf_to_str_buf(ctx, lang));
- else
- ret = pdf_document_language(ctx, annot->page->doc);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_language(fz_context *ctx, pdf_annot *annot, fz_text_language lang)
- {
- char buf[8];
- begin_annot_op(ctx, annot, "Set language");
- fz_try(ctx)
- {
- if (lang == FZ_LANG_UNSET)
- pdf_dict_del(ctx, annot->obj, PDF_NAME(Lang));
- else
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Lang), fz_string_from_text_language(buf, lang));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- static pdf_obj *quadding_subtypes[] = {
- PDF_NAME(FreeText),
- PDF_NAME(Widget),
- NULL,
- };
- int
- pdf_annot_has_quadding(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Q), quadding_subtypes);
- }
- int
- pdf_annot_quadding(fz_context *ctx, pdf_annot *annot)
- {
- int q;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Q), quadding_subtypes);
- q = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Q));
- q = (q < 0 || q > 2) ? 0 : q;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return q;
- }
- void
- pdf_set_annot_quadding(fz_context *ctx, pdf_annot *annot, int q)
- {
- q = (q < 0 || q > 2) ? 0 : q;
- begin_annot_op(ctx, annot, "Set quadding");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Q), quadding_subtypes);
- pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Q), q);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- float pdf_annot_opacity(fz_context *ctx, pdf_annot *annot)
- {
- float ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- ret = pdf_dict_get_real_default(ctx, annot->obj, PDF_NAME(CA), 1);
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void pdf_set_annot_opacity(fz_context *ctx, pdf_annot *annot, float opacity)
- {
- begin_annot_op(ctx, annot, "Set opacity");
- fz_try(ctx)
- {
- if (opacity != 1)
- pdf_dict_put_real(ctx, annot->obj, PDF_NAME(CA), opacity);
- else
- pdf_dict_del(ctx, annot->obj, PDF_NAME(CA));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- static void pdf_annot_color_imp(fz_context *ctx, pdf_obj *arr, int *n, float color[4])
- {
- switch (pdf_array_len(ctx, arr))
- {
- case 0:
- if (n)
- *n = 0;
- break;
- case 1:
- case 2:
- if (n)
- *n = 1;
- if (color)
- color[0] = pdf_array_get_real(ctx, arr, 0);
- break;
- case 3:
- if (n)
- *n = 3;
- if (color)
- {
- color[0] = pdf_array_get_real(ctx, arr, 0);
- color[1] = pdf_array_get_real(ctx, arr, 1);
- color[2] = pdf_array_get_real(ctx, arr, 2);
- }
- break;
- case 4:
- default:
- if (n)
- *n = 4;
- if (color)
- {
- color[0] = pdf_array_get_real(ctx, arr, 0);
- color[1] = pdf_array_get_real(ctx, arr, 1);
- color[2] = pdf_array_get_real(ctx, arr, 2);
- color[3] = pdf_array_get_real(ctx, arr, 3);
- }
- break;
- }
- }
- static int pdf_annot_color_rgb(fz_context *ctx, pdf_obj *arr, float rgb[3])
- {
- float color[4];
- int n;
- pdf_annot_color_imp(ctx, arr, &n, color);
- if (n == 0)
- {
- return 0;
- }
- else if (n == 1)
- {
- rgb[0] = rgb[1] = rgb[2] = color[0];
- }
- else if (n == 3)
- {
- rgb[0] = color[0];
- rgb[1] = color[1];
- rgb[2] = color[2];
- }
- else if (n == 4)
- {
- rgb[0] = 1 - fz_min(1, color[0] + color[3]);
- rgb[1] = 1 - fz_min(1, color[1] + color[3]);
- rgb[2] = 1 - fz_min(1, color[2] + color[3]);
- }
- return 1;
- }
- static void pdf_set_annot_color_imp(fz_context *ctx, pdf_annot *annot, pdf_obj *key, int n, const float *color, pdf_obj **allowed)
- {
- pdf_obj *arr;
- if (allowed)
- check_allowed_subtypes(ctx, annot, key, allowed);
- if (n != 0 && n != 1 && n != 3 && n != 4)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "color must be 0, 1, 3 or 4 components");
- if (!color)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "no color given");
- arr = pdf_dict_put_array(ctx, annot->obj, key, n);
- fz_try(ctx)
- {
- switch (n)
- {
- case 1:
- pdf_array_push_real(ctx, arr, color[0]);
- break;
- case 3:
- pdf_array_push_real(ctx, arr, color[0]);
- pdf_array_push_real(ctx, arr, color[1]);
- pdf_array_push_real(ctx, arr, color[2]);
- break;
- case 4:
- pdf_array_push_real(ctx, arr, color[0]);
- pdf_array_push_real(ctx, arr, color[1]);
- pdf_array_push_real(ctx, arr, color[2]);
- pdf_array_push_real(ctx, arr, color[3]);
- break;
- }
- }
- fz_catch(ctx)
- fz_rethrow(ctx);
- pdf_dirty_annot(ctx, annot);
- }
- static void
- do_pdf_annot_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4], pdf_obj *name)
- {
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *c = pdf_dict_get(ctx, annot->obj, name);
- pdf_annot_color_imp(ctx, c, n, color);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- void
- pdf_annot_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
- {
- do_pdf_annot_color(ctx, annot, n, color, PDF_NAME(C));
- }
- void
- pdf_annot_MK_BG(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
- {
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG));
- pdf_annot_color_imp(ctx, mk_bg, n, color);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- int
- pdf_annot_MK_BG_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3])
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG));
- ret = pdf_annot_color_rgb(ctx, mk_bg, rgb);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_annot_MK_BC(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
- {
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC));
- pdf_annot_color_imp(ctx, mk_bc, n, color);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- int
- pdf_annot_MK_BC_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3])
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC));
- ret = pdf_annot_color_rgb(ctx, mk_bc, rgb);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_color(fz_context *ctx, pdf_annot *annot, int n, const float *color)
- {
- begin_annot_op(ctx, annot, "Set color");
- fz_try(ctx)
- {
- pdf_set_annot_color_imp(ctx, annot, PDF_NAME(C), n, color, NULL);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *interior_color_subtypes[] = {
- PDF_NAME(Circle),
- PDF_NAME(Line),
- PDF_NAME(PolyLine),
- PDF_NAME(Polygon),
- PDF_NAME(Square),
- NULL,
- };
- int
- pdf_annot_has_interior_color(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(IC), interior_color_subtypes);
- }
- void
- pdf_annot_interior_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4])
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(IC), interior_color_subtypes);
- do_pdf_annot_color(ctx, annot, n, color, PDF_NAME(IC));
- }
- void
- pdf_set_annot_interior_color(fz_context *ctx, pdf_annot *annot, int n, const float *color)
- {
- begin_annot_op(ctx, annot, "Set interior color");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(IC), interior_color_subtypes);
- pdf_set_annot_color_imp(ctx, annot, PDF_NAME(IC), n, color, interior_color_subtypes);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *line_subtypes[] = {
- PDF_NAME(Line),
- NULL,
- };
- int
- pdf_annot_has_line(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(L), line_subtypes);
- }
- void
- pdf_annot_line(fz_context *ctx, pdf_annot *annot, fz_point *a, fz_point *b)
- {
- fz_matrix page_ctm;
- pdf_obj *line;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- line = pdf_dict_get(ctx, annot->obj, PDF_NAME(L));
- a->x = pdf_array_get_real(ctx, line, 0);
- a->y = pdf_array_get_real(ctx, line, 1);
- b->x = pdf_array_get_real(ctx, line, 2);
- b->y = pdf_array_get_real(ctx, line, 3);
- *a = fz_transform_point(*a, page_ctm);
- *b = fz_transform_point(*b, page_ctm);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- void
- pdf_set_annot_line(fz_context *ctx, pdf_annot *annot, fz_point a, fz_point b)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *line;
- begin_annot_op(ctx, annot, "Set line");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- a = fz_transform_point(a, inv_page_ctm);
- b = fz_transform_point(b, inv_page_ctm);
- line = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(L), 4);
- pdf_array_push_real(ctx, line, a.x);
- pdf_array_push_real(ctx, line, a.y);
- pdf_array_push_real(ctx, line, b.x);
- pdf_array_push_real(ctx, line, b.y);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- float
- pdf_annot_line_leader(fz_context *ctx, pdf_annot *annot)
- {
- float value;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LL), line_subtypes);
- value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LL));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return value;
- }
- float
- pdf_annot_line_leader_extension(fz_context *ctx, pdf_annot *annot)
- {
- float value;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LLE), line_subtypes);
- value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LLE));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return value;
- }
- float
- pdf_annot_line_leader_offset(fz_context *ctx, pdf_annot *annot)
- {
- float value;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LLO), line_subtypes);
- value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LLO));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return value;
- }
- void
- pdf_set_annot_line_leader(fz_context *ctx, pdf_annot *annot, float value)
- {
- begin_annot_op(ctx, annot, "Set line leader");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LL), line_subtypes);
- if (value)
- pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LL), value);
- else
- pdf_dict_del(ctx, annot->obj, PDF_NAME(LL));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_line_leader_extension(fz_context *ctx, pdf_annot *annot, float value)
- {
- begin_annot_op(ctx, annot, "Set line leader_extension");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LLE), line_subtypes);
- if (value)
- pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LLE), value);
- else
- pdf_dict_del(ctx, annot->obj, PDF_NAME(LLE));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_set_annot_line_leader_offset(fz_context *ctx, pdf_annot *annot, float value)
- {
- begin_annot_op(ctx, annot, "Set line leader offset");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(LLO), line_subtypes);
- if (value)
- pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LLO), value);
- else
- pdf_dict_del(ctx, annot->obj, PDF_NAME(LLO));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- int
- pdf_annot_line_caption(fz_context *ctx, pdf_annot *annot)
- {
- int cap = 0;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Cap), line_subtypes);
- cap = pdf_dict_get_bool(ctx, annot->obj, PDF_NAME(Cap));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return cap;
- }
- void
- pdf_set_annot_line_caption(fz_context *ctx, pdf_annot *annot, int cap)
- {
- begin_annot_op(ctx, annot, "Set line caption");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Cap), line_subtypes);
- pdf_dict_put_bool(ctx, annot->obj, PDF_NAME(Cap), cap);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- fz_point
- pdf_annot_line_caption_offset(fz_context *ctx, pdf_annot *annot)
- {
- fz_point offset = fz_make_point(0, 0);
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(CO), line_subtypes);
- offset = pdf_dict_get_point(ctx, annot->obj, PDF_NAME(CO));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return offset;
- }
- void
- pdf_set_annot_line_caption_offset(fz_context *ctx, pdf_annot *annot, fz_point offset)
- {
- begin_annot_op(ctx, annot, "Set line caption");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(CO), line_subtypes);
- if (offset.x == 0 && offset.y == 0)
- pdf_dict_del(ctx, annot->obj, PDF_NAME(CO));
- else
- pdf_dict_put_point(ctx, annot->obj, PDF_NAME(CO), offset);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- static pdf_obj *vertices_subtypes[] = {
- PDF_NAME(PolyLine),
- PDF_NAME(Polygon),
- NULL,
- };
- int
- pdf_annot_has_vertices(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- }
- int
- pdf_annot_vertex_count(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *vertices;
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
- ret = pdf_array_len(ctx, vertices) / 2;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- fz_point
- pdf_annot_vertex(fz_context *ctx, pdf_annot *annot, int i)
- {
- pdf_obj *vertices;
- fz_matrix page_ctm;
- fz_point point;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- point.x = pdf_array_get_real(ctx, vertices, i * 2);
- point.y = pdf_array_get_real(ctx, vertices, i * 2 + 1);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return fz_transform_point(point, page_ctm);
- }
- void
- pdf_set_annot_vertices(fz_context *ctx, pdf_annot *annot, int n, const fz_point *v)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *vertices;
- fz_point point;
- int i;
- begin_annot_op(ctx, annot, "Set points");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- if (n <= 0 || !v)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid number of vertices");
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- vertices = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(Vertices), n * 2);
- for (i = 0; i < n; ++i)
- {
- point = fz_transform_point(v[i], inv_page_ctm);
- pdf_array_push_real(ctx, vertices, point.x);
- pdf_array_push_real(ctx, vertices, point.y);
- }
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_clear_annot_vertices(fz_context *ctx, pdf_annot *annot)
- {
- begin_annot_op(ctx, annot, "Clear vertices");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- pdf_dict_del(ctx, annot->obj, PDF_NAME(Vertices));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_add_annot_vertex(fz_context *ctx, pdf_annot *annot, fz_point p)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *vertices;
- begin_annot_op(ctx, annot, "Add point");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
- if (!pdf_is_array(ctx, vertices))
- vertices = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(Vertices), 32);
- p = fz_transform_point(p, inv_page_ctm);
- pdf_array_push_real(ctx, vertices, p.x);
- pdf_array_push_real(ctx, vertices, p.y);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_set_annot_vertex(fz_context *ctx, pdf_annot *annot, int i, fz_point p)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *vertices;
- begin_annot_op(ctx, annot, "Set point");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- p = fz_transform_point(p, inv_page_ctm);
- vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices));
- pdf_array_put_real(ctx, vertices, i * 2 + 0, p.x);
- pdf_array_put_real(ctx, vertices, i * 2 + 1, p.x);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *quad_point_subtypes[] = {
- PDF_NAME(Highlight),
- PDF_NAME(Link),
- PDF_NAME(Squiggly),
- PDF_NAME(StrikeOut),
- PDF_NAME(Underline),
- PDF_NAME(Redact),
- NULL,
- };
- int
- pdf_annot_has_quad_points(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- }
- int
- pdf_annot_quad_point_count(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *quad_points;
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
- ret = pdf_array_len(ctx, quad_points) / 8;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- fz_quad
- pdf_annot_quad_point(fz_context *ctx, pdf_annot *annot, int idx)
- {
- pdf_obj *quad_points;
- fz_matrix page_ctm;
- float v[8];
- int i;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- for (i = 0; i < 8; i += 2)
- {
- fz_point point;
- point.x = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 0);
- point.y = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 1);
- point = fz_transform_point(point, page_ctm);
- v[i+0] = point.x;
- v[i+1] = point.y;
- }
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return fz_make_quad(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
- }
- void
- pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const fz_quad *q)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *quad_points;
- fz_quad quad;
- int i;
- begin_annot_op(ctx, annot, "Set quad points");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- if (n <= 0 || !q)
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid number of quadrilaterals");
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- quad_points = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(QuadPoints), n);
- for (i = 0; i < n; ++i)
- {
- quad = fz_transform_quad(q[i], inv_page_ctm);
- pdf_array_push_real(ctx, quad_points, quad.ul.x);
- pdf_array_push_real(ctx, quad_points, quad.ul.y);
- pdf_array_push_real(ctx, quad_points, quad.ur.x);
- pdf_array_push_real(ctx, quad_points, quad.ur.y);
- pdf_array_push_real(ctx, quad_points, quad.ll.x);
- pdf_array_push_real(ctx, quad_points, quad.ll.y);
- pdf_array_push_real(ctx, quad_points, quad.lr.x);
- pdf_array_push_real(ctx, quad_points, quad.lr.y);
- }
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_clear_annot_quad_points(fz_context *ctx, pdf_annot *annot)
- {
- begin_annot_op(ctx, annot, "Clear quad points");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- pdf_dict_del(ctx, annot->obj, PDF_NAME(QuadPoints));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_quad quad)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *quad_points;
- begin_annot_op(ctx, annot, "Add quad point");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints));
- if (!pdf_is_array(ctx, quad_points))
- quad_points = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(QuadPoints), 8);
- /* Contrary to the specification, the points within a QuadPoint are NOT ordered
- * in a counterclockwise fashion. Experiments with Adobe's implementation
- * indicates a cross-wise ordering is intended: ul, ur, ll, lr.
- */
- quad = fz_transform_quad(quad, inv_page_ctm);
- pdf_array_push_real(ctx, quad_points, quad.ul.x);
- pdf_array_push_real(ctx, quad_points, quad.ul.y);
- pdf_array_push_real(ctx, quad_points, quad.ur.x);
- pdf_array_push_real(ctx, quad_points, quad.ur.y);
- pdf_array_push_real(ctx, quad_points, quad.ll.x);
- pdf_array_push_real(ctx, quad_points, quad.ll.y);
- pdf_array_push_real(ctx, quad_points, quad.lr.x);
- pdf_array_push_real(ctx, quad_points, quad.lr.y);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- static pdf_obj *ink_list_subtypes[] = {
- PDF_NAME(Ink),
- NULL,
- };
- int
- pdf_annot_has_ink_list(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- }
- int
- pdf_annot_ink_list_count(fz_context *ctx, pdf_annot *annot)
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- pdf_obj *ink_list;
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- ret = pdf_array_len(ctx, ink_list);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- int
- pdf_annot_ink_list_stroke_count(fz_context *ctx, pdf_annot *annot, int i)
- {
- pdf_obj *ink_list;
- pdf_obj *stroke;
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- stroke = pdf_array_get(ctx, ink_list, i);
- ret = pdf_array_len(ctx, stroke) / 2;
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- fz_point
- pdf_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, int i, int k)
- {
- pdf_obj *ink_list;
- pdf_obj *stroke;
- fz_matrix page_ctm;
- fz_point point;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- stroke = pdf_array_get(ctx, ink_list, i);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- point.x = pdf_array_get_real(ctx, stroke, k * 2 + 0);
- point.y = pdf_array_get_real(ctx, stroke, k * 2 + 1);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return fz_transform_point(point, page_ctm);
- }
- /* FIXME: try/catch required for memory exhaustion */
- void
- pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const fz_point *v)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *ink_list = NULL, *stroke;
- fz_point point;
- int i, k;
- fz_var(ink_list);
- begin_annot_op(ctx, annot, "Set ink list");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), n);
- for (i = 0; i < n; ++i)
- {
- stroke = pdf_array_push_array(ctx, ink_list, count[i] * 2);
- /* Although we have dropped our reference to stroke,
- * it's still valid because we ink_list holds one, and
- * we hold a reference to that. */
- for (k = 0; k < count[i]; ++k)
- {
- point = fz_transform_point(*v++, inv_page_ctm);
- pdf_array_push_real(ctx, stroke, point.x);
- pdf_array_push_real(ctx, stroke, point.y);
- }
- }
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_clear_annot_ink_list(fz_context *ctx, pdf_annot *annot)
- {
- begin_annot_op(ctx, annot, "Clear ink list");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- pdf_dict_del(ctx, annot->obj, PDF_NAME(InkList));
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_add_annot_ink_list_stroke(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *ink_list;
- begin_annot_op(ctx, annot, "Add ink list stroke");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- if (!pdf_is_array(ctx, ink_list))
- ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10);
- pdf_array_push_array(ctx, ink_list, 16);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_add_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, fz_point p)
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *ink_list, *stroke;
- begin_annot_op(ctx, annot, "Add ink list stroke point");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- if (!pdf_is_array(ctx, ink_list))
- ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10);
- stroke = pdf_array_get(ctx, ink_list, pdf_array_len(ctx, ink_list)-1);
- if (!pdf_is_array(ctx, stroke))
- {
- int len = pdf_array_len(ctx, ink_list);
- stroke = pdf_new_array(ctx, pdf_get_bound_document(ctx, ink_list), 16);
- pdf_array_put_drop(ctx, ink_list, len ? len-1 : 0, stroke);
- }
- p = fz_transform_point(p, inv_page_ctm);
- pdf_array_push_real(ctx, stroke, p.x);
- pdf_array_push_real(ctx, stroke, p.y);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void
- pdf_add_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, fz_point p[])
- {
- fz_matrix page_ctm, inv_page_ctm;
- pdf_obj *ink_list, *stroke;
- int i;
- begin_annot_op(ctx, annot, "Add ink list");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- inv_page_ctm = fz_invert_matrix(page_ctm);
- ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList));
- if (!pdf_is_array(ctx, ink_list))
- ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10);
- stroke = pdf_array_push_array(ctx, ink_list, n * 2);
- for (i = 0; i < n; ++i)
- {
- fz_point tp = fz_transform_point(p[i], inv_page_ctm);
- pdf_array_push_real(ctx, stroke, tp.x);
- pdf_array_push_real(ctx, stroke, tp.y);
- }
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- /*
- Get annotation's modification date in seconds since the epoch.
- */
- int64_t
- pdf_annot_modification_date(fz_context *ctx, pdf_annot *annot)
- {
- int64_t ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(M));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- /*
- Get annotation's creation date in seconds since the epoch.
- */
- int64_t
- pdf_annot_creation_date(fz_context *ctx, pdf_annot *annot)
- {
- int64_t ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(CreationDate));
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- /*
- Set annotation's modification date in seconds since the epoch.
- */
- void
- pdf_set_annot_modification_date(fz_context *ctx, pdf_annot *annot, int64_t secs)
- {
- begin_annot_op(ctx, annot, "Set modification date");
- fz_try(ctx)
- {
- pdf_dict_put_date(ctx, annot->obj, PDF_NAME(M), secs);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- /*
- Set annotation's creation date in seconds since the epoch.
- */
- void
- pdf_set_annot_creation_date(fz_context *ctx, pdf_annot *annot, int64_t secs)
- {
- begin_annot_op(ctx, annot, "Set creation date");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(CreationDate), markup_subtypes);
- pdf_dict_put_date(ctx, annot->obj, PDF_NAME(CreationDate), secs);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- int
- pdf_annot_has_author(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(T), markup_subtypes);
- }
- const char *
- pdf_annot_author(fz_context *ctx, pdf_annot *annot)
- {
- const char *ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes);
- ret = pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(T));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_author(fz_context *ctx, pdf_annot *annot, const char *author)
- {
- begin_annot_op(ctx, annot, "Set author");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes);
- pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(T), author);
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *intent_subtypes[] = {
- PDF_NAME(FreeText),
- PDF_NAME(Line),
- PDF_NAME(Polygon),
- PDF_NAME(PolyLine),
- PDF_NAME(Stamp),
- NULL,
- };
- enum pdf_intent pdf_intent_from_name(fz_context *ctx, pdf_obj *it)
- {
- if (
- it == PDF_NULL ||
- it == PDF_NAME(FreeText) ||
- it == PDF_NAME(Line) ||
- it == PDF_NAME(PolyLine) ||
- it == PDF_NAME(Polygon) ||
- it == PDF_NAME(Stamp)
- )
- return PDF_ANNOT_IT_DEFAULT;
- if (it == PDF_NAME(FreeTextCallout))
- return PDF_ANNOT_IT_FREETEXT_CALLOUT;
- if (it == PDF_NAME(FreeTextTypeWriter))
- return PDF_ANNOT_IT_FREETEXT_TYPEWRITER;
- if (it == PDF_NAME(LineArrow))
- return PDF_ANNOT_IT_LINE_ARROW;
- if (it == PDF_NAME(LineDimension))
- return PDF_ANNOT_IT_LINE_DIMENSION;
- if (it == PDF_NAME(PolyLineDimension))
- return PDF_ANNOT_IT_POLYLINE_DIMENSION;
- if (it == PDF_NAME(PolygonCloud))
- return PDF_ANNOT_IT_POLYGON_CLOUD;
- if (it == PDF_NAME(PolygonDimension))
- return PDF_ANNOT_IT_POLYGON_DIMENSION;
- if (it == PDF_NAME(StampImage))
- return PDF_ANNOT_IT_STAMP_IMAGE;
- if (it == PDF_NAME(StampSnapshot))
- return PDF_ANNOT_IT_STAMP_SNAPSHOT;
- return PDF_ANNOT_IT_UNKNOWN;
- }
- enum pdf_intent pdf_intent_from_string(fz_context *ctx, const char *it)
- {
- if (
- it == NULL ||
- !strcmp(it, "FreeText") ||
- !strcmp(it, "Line") ||
- !strcmp(it, "PolyLine") ||
- !strcmp(it, "Polygon") ||
- !strcmp(it, "Stamp")
- )
- return PDF_ANNOT_IT_DEFAULT;
- if (!strcmp(it, "FreeTextCallout"))
- return PDF_ANNOT_IT_FREETEXT_CALLOUT;
- if (!strcmp(it, "FreeTextTypeWriter"))
- return PDF_ANNOT_IT_FREETEXT_TYPEWRITER;
- if (!strcmp(it, "LineArrow"))
- return PDF_ANNOT_IT_LINE_ARROW;
- if (!strcmp(it, "LineDimension"))
- return PDF_ANNOT_IT_LINE_DIMENSION;
- if (!strcmp(it, "PolyLineDimension"))
- return PDF_ANNOT_IT_POLYLINE_DIMENSION;
- if (!strcmp(it, "PolygonCloud"))
- return PDF_ANNOT_IT_POLYGON_CLOUD;
- if (!strcmp(it, "PolygonDimension"))
- return PDF_ANNOT_IT_POLYGON_DIMENSION;
- if (!strcmp(it, "StampImage"))
- return PDF_ANNOT_IT_STAMP_IMAGE;
- if (!strcmp(it, "StampSnapshot"))
- return PDF_ANNOT_IT_STAMP_SNAPSHOT;
- return PDF_ANNOT_IT_UNKNOWN;
- }
- pdf_obj *pdf_name_from_intent(fz_context *ctx, enum pdf_intent it)
- {
- switch (it)
- {
- default:
- case PDF_ANNOT_IT_DEFAULT: return PDF_NULL;
- case PDF_ANNOT_IT_FREETEXT_CALLOUT: return PDF_NAME(FreeTextCallout);
- case PDF_ANNOT_IT_FREETEXT_TYPEWRITER: return PDF_NAME(FreeTextTypeWriter);
- case PDF_ANNOT_IT_LINE_ARROW: return PDF_NAME(LineArrow);
- case PDF_ANNOT_IT_LINE_DIMENSION: return PDF_NAME(LineDimension);
- case PDF_ANNOT_IT_POLYLINE_DIMENSION: return PDF_NAME(PolyLineDimension);
- case PDF_ANNOT_IT_POLYGON_CLOUD: return PDF_NAME(PolygonCloud);
- case PDF_ANNOT_IT_POLYGON_DIMENSION: return PDF_NAME(PolygonDimension);
- }
- }
- const char *pdf_string_from_intent(fz_context *ctx, enum pdf_intent it)
- {
- switch (it)
- {
- default:
- case PDF_ANNOT_IT_DEFAULT: return NULL;
- case PDF_ANNOT_IT_FREETEXT_CALLOUT: return "FreeTextCallout";
- case PDF_ANNOT_IT_FREETEXT_TYPEWRITER: return "FreeTextTypeWriter";
- case PDF_ANNOT_IT_LINE_ARROW: return "LineArrow";
- case PDF_ANNOT_IT_LINE_DIMENSION: return "LineDimension";
- case PDF_ANNOT_IT_POLYLINE_DIMENSION: return "PolyLineDimension";
- case PDF_ANNOT_IT_POLYGON_CLOUD: return "PolygonCloud";
- case PDF_ANNOT_IT_POLYGON_DIMENSION: return "PolygonDimension";
- }
- }
- int
- pdf_annot_has_intent(fz_context *ctx, pdf_annot *annot)
- {
- /* Only a subset of intents are defined in the spec, so we limit this API to the defined ones.
- * FreeText: Callout, TypeWriter
- * Line: Arrow, Dimension
- * Polygon: Cloud, Dimension
- * PolyLine: Dimension
- */
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(IT), intent_subtypes);
- }
- enum pdf_intent
- pdf_annot_intent(fz_context *ctx, pdf_annot *annot)
- {
- enum pdf_intent ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(IT), intent_subtypes);
- ret = pdf_intent_from_name(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(IT)));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- void
- pdf_set_annot_intent(fz_context *ctx, pdf_annot *annot, enum pdf_intent it)
- {
- begin_annot_op(ctx, annot, "Set intent");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(IT), intent_subtypes);
- pdf_dict_put(ctx, annot->obj, PDF_NAME(IT), pdf_name_from_intent(ctx, it));
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *callout_subtypes[] = {
- PDF_NAME(FreeText),
- NULL,
- };
- int pdf_annot_has_callout(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(CL), callout_subtypes);
- }
- enum pdf_line_ending pdf_annot_callout_style(fz_context *ctx, pdf_annot *annot)
- {
- enum pdf_line_ending style = PDF_ANNOT_LE_NONE;
- pdf_obj *obj;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes);
- obj = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE));
- style = pdf_line_ending_from_name(ctx, obj);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return style;
- }
- void pdf_set_annot_callout_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending style)
- {
- begin_annot_op(ctx, annot, "Set callout style");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes);
- pdf_dict_put(ctx, annot->obj, PDF_NAME(LE), pdf_name_from_line_ending(ctx, style));
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_annot_callout_line(fz_context *ctx, pdf_annot *annot, fz_point callout[3], int *np)
- {
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- fz_matrix page_ctm;
- pdf_obj *obj;
- int n;
- check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes);
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- obj = pdf_dict_get(ctx, annot->obj, PDF_NAME(CL));
- n = pdf_array_len(ctx, obj);
- if (n == 4 || n == 6)
- {
- callout[0] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 0), pdf_array_get_real(ctx, obj, 1), page_ctm);
- callout[1] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 2), pdf_array_get_real(ctx, obj, 3), page_ctm);
- if (n == 4)
- {
- *np = 2;
- callout[2] = fz_make_point(0, 0);
- }
- else
- {
- *np = 3;
- callout[2] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 4), pdf_array_get_real(ctx, obj, 5), page_ctm);
- }
- }
- else
- {
- callout[0] = fz_make_point(0, 0);
- callout[1] = fz_make_point(0, 0);
- callout[2] = fz_make_point(0, 0);
- *np = 0;
- }
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- void pdf_set_annot_callout_line(fz_context *ctx, pdf_annot *annot, fz_point callout[3], int n)
- {
- begin_annot_op(ctx, annot, "Set callout");
- fz_try(ctx)
- {
- fz_matrix page_ctm;
- fz_point p;
- int i;
- pdf_obj *obj;
- check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes);
- if (n == 2 || n == 3)
- {
- pdf_page_transform(ctx, annot->page, NULL, &page_ctm);
- obj = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(CL), n * 2);
- for (i = 0; i < n; ++i)
- {
- p = fz_transform_point(callout[i], page_ctm);
- pdf_array_push_real(ctx, obj, p.x);
- pdf_array_push_real(ctx, obj, p.y);
- }
- }
- else
- {
- pdf_dict_del(ctx, annot->obj, PDF_NAME(CL));
- }
- pdf_dirty_annot(ctx, annot);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- fz_point pdf_annot_callout_point(fz_context *ctx, pdf_annot *annot)
- {
- fz_point line[3];
- int n;
- pdf_annot_callout_line(ctx, annot, line, &n);
- if (n > 0)
- return line[0];
- return fz_make_point(0, 0);
- }
- void pdf_set_annot_callout_point(fz_context *ctx, pdf_annot *annot, fz_point p)
- {
- fz_rect rect;
- fz_point a, b, line[3];
- float m;
- rect = pdf_annot_rect(ctx, annot);
- // Make line from center of text box to designated end point.
- a = fz_make_point((rect.x0 + rect.x1) / 2, (rect.y0 + rect.y1) / 2);
- b = p;
- // No CalloutLine if end point is within the text box itself.
- if (fz_is_point_inside_rect(p, rect))
- {
- line[0] = p;
- line[1] = a;
- pdf_set_annot_callout_line(ctx, annot, line, 2);
- return;
- }
- // Simplified Cohen-Sutherland algorithm to find intersection of line and text box.
- m = (b.y - a.y) / (b.x - a.x);
- for (;;)
- {
- if (b.y < rect.y0) {
- b.x = a.x + (rect.y0 - a.y) / m;
- b.y = rect.y0;
- }
- else
- if (b.y > rect.y1) {
- b.x = a.x + (rect.y1 - a.y) / m;
- b.y = rect.y1;
- }
- else
- if (b.x < rect.x0) {
- b.y = a.y + (rect.x0 - a.x) * m;
- b.x = rect.x0;
- }
- else
- if (b.x > rect.x1) {
- b.y = a.y + (rect.x1 - a.x) * m;
- b.x = rect.x1;
- }
- else
- break;
- }
- // Draw line from intersection to end point.
- line[0] = p;
- line[1] = b;
- pdf_set_annot_callout_line(ctx, annot, line, 2);
- }
- void
- pdf_parse_default_appearance_unmapped(fz_context *ctx, const char *da, char *font_name, int font_name_size, float *size, int *n, float color[4])
- {
- char buf[100], *p = buf, *tok, *end;
- float stack[4] = { 0, 0, 0, 0 };
- int top = 0;
- fz_strlcpy(font_name, "Helv", font_name_size);
- *size = 12;
- *n = 0;
- color[0] = color[1] = color[2] = color[3] = 0;
- fz_strlcpy(buf, da, sizeof buf);
- while ((tok = fz_strsep(&p, " \n\r\t")) != NULL)
- {
- if (tok[0] == 0)
- ;
- else if (tok[0] == '/')
- {
- fz_strlcpy(font_name, tok+1, font_name_size);
- }
- else if (!strcmp(tok, "Tf"))
- {
- *size = stack[0];
- top = 0;
- }
- else if (!strcmp(tok, "g"))
- {
- *n = 1;
- color[0] = stack[0];
- top = 0;
- }
- else if (!strcmp(tok, "rg"))
- {
- *n = 3;
- color[0] = stack[0];
- color[1] = stack[1];
- color[2] = stack[2];
- top=0;
- }
- else if (!strcmp(tok, "k"))
- {
- *n = 4;
- color[0] = stack[0];
- color[1] = stack[1];
- color[2] = stack[2];
- color[3] = stack[3];
- top=0;
- }
- else
- {
- float v = fz_strtof(tok, &end);
- if (top < 4)
- stack[top] = v;
- if (*end == 0)
- ++top;
- else
- top = 0;
- }
- }
- }
- void
- pdf_parse_default_appearance(fz_context *ctx, const char *da, const char **font, float *size, int *n, float color[4])
- {
- char font_name[100];
- pdf_parse_default_appearance_unmapped(ctx, da, font_name, sizeof font_name, size, n, color);
- if (!strcmp(font_name, "Cour")) *font = "Cour";
- else if (!strcmp(font_name, "Helv")) *font = "Helv";
- else if (!strcmp(font_name, "TiRo")) *font = "TiRo";
- else if (!strcmp(font_name, "Symb")) *font = "Symb";
- else if (!strcmp(font_name, "ZaDb")) *font = "ZaDb";
- else *font = "Helv";
- }
- void
- pdf_print_default_appearance(fz_context *ctx, char *buf, int nbuf, const char *font, float size, int n, const float *color)
- {
- if (n == 4)
- fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g %g k", font, size, color[0], color[1], color[2], color[3]);
- else if (n == 3)
- fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g rg", font, size, color[0], color[1], color[2]);
- else if (n == 1)
- fz_snprintf(buf, nbuf, "/%s %g Tf %g g", font, size, color[0]);
- else
- fz_snprintf(buf, nbuf, "/%s %g Tf", font, size);
- }
- void
- pdf_annot_default_appearance_unmapped(fz_context *ctx, pdf_annot *annot, char *font_name, int font_name_len, float *size, int *n, float color[4])
- {
- pdf_obj *da;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- da = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(DA));
- if (!da)
- {
- pdf_obj *trailer = pdf_trailer(ctx, annot->page->doc);
- da = pdf_dict_getl(ctx, trailer, PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DA), NULL);
- }
- pdf_parse_default_appearance_unmapped(ctx, pdf_to_str_buf(ctx, da), font_name, font_name_len, size, n, color);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- static pdf_obj *default_appearance_subtypes[] = {
- PDF_NAME(FreeText),
- PDF_NAME(Widget),
- NULL,
- };
- int
- pdf_annot_has_default_appearance(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(DA), default_appearance_subtypes);
- }
- void
- pdf_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char **font, float *size, int *n, float color[4])
- {
- pdf_obj *da;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(DA), default_appearance_subtypes);
- da = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(DA));
- if (!da)
- {
- pdf_obj *trailer = pdf_trailer(ctx, annot->page->doc);
- da = pdf_dict_getl(ctx, trailer, PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DA), NULL);
- }
- pdf_parse_default_appearance(ctx, pdf_to_str_buf(ctx, da), font, size, n, color);
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- void
- pdf_set_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char *font, float size, int n, const float *color)
- {
- char buf[100];
- begin_annot_op(ctx, annot, "Set default appearance");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(DA), default_appearance_subtypes);
- pdf_print_default_appearance(ctx, buf, sizeof buf, font, size, n, color);
- pdf_dict_put_string(ctx, annot->obj, PDF_NAME(DA), buf, strlen(buf));
- pdf_dict_del(ctx, annot->obj, PDF_NAME(DS)); /* not supported */
- pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- int pdf_annot_field_flags(fz_context *ctx, pdf_annot *annot)
- {
- int ret;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- ret = pdf_field_flags(ctx, annot->obj);
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- const char *pdf_annot_field_value(fz_context *ctx, pdf_annot *widget)
- {
- const char *ret;
- pdf_annot_push_local_xref(ctx, widget);
- fz_try(ctx)
- ret = pdf_field_value(ctx, widget->obj);
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, widget);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- const char *pdf_annot_field_label(fz_context *ctx, pdf_annot *widget)
- {
- const char *ret;
- pdf_annot_push_local_xref(ctx, widget);
- fz_try(ctx)
- ret = pdf_field_label(ctx, widget->obj);
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, widget);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return ret;
- }
- int pdf_set_annot_field_value(fz_context *ctx, pdf_document *doc, pdf_annot *annot, const char *text, int ignore_trigger_events)
- {
- int ret;
- begin_annot_op(ctx, annot, "Set field value");
- fz_try(ctx)
- {
- ret = pdf_set_field_value(ctx, doc, annot->obj, text, ignore_trigger_events);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- return ret;
- }
- void
- pdf_set_annot_appearance(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_rect bbox, pdf_obj *res, fz_buffer *contents)
- {
- pdf_obj *form = NULL;
- pdf_obj *ap, *app;
- pdf_obj *app_name = NULL;
- begin_annot_op(ctx, annot, "Set appearance stream");
- if (!appearance)
- appearance = "N";
- fz_var(form);
- fz_var(app_name);
- fz_try(ctx)
- {
- ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP));
- if (!ap)
- ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 1);
- if (!state)
- form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance));
- else
- {
- if (strcmp(appearance, "N") && strcmp(appearance, "R") && strcmp(appearance, "D"))
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unknown annotation appearance");
- app_name = pdf_new_name(ctx, appearance);
- app = pdf_dict_get(ctx, ap, app_name);
- if (!app)
- app = pdf_dict_put_dict(ctx, ap, app_name, 2);
- form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance));
- }
- /* Care required here. Some files have multiple annotations, which share
- * appearance streams. As such, we must NOT reuse such appearance streams.
- * On the other hand, we cannot afford to always recreate appearance
- * streams, as this can lead to leakage of partial edits into the document.
- * Any appearance we generate will be in the incremental section, and we
- * will never generate shared appearances. As such, we can reuse an
- * appearance object only if it is in the incremental section. */
- if (!pdf_obj_is_incremental(ctx, form))
- {
- pdf_drop_obj(ctx, form);
- form = NULL;
- }
- if (!pdf_is_dict(ctx, form))
- {
- pdf_drop_obj(ctx, form);
- form = NULL;
- form = pdf_new_xobject(ctx, annot->page->doc, bbox, ctm, res, contents);
- }
- else
- pdf_update_xobject(ctx, annot->page->doc, form, bbox, ctm, res, contents);
- if (!state)
- pdf_dict_puts(ctx, ap, appearance, form);
- else
- pdf_dict_puts(ctx, app, state, form);
- end_annot_op(ctx, annot);
- }
- fz_always(ctx)
- {
- pdf_drop_obj(ctx, form);
- pdf_drop_obj(ctx, app_name);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_set_annot_resynthesised(ctx, annot);
- }
- void
- pdf_set_annot_appearance_from_display_list(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_display_list *list)
- {
- pdf_document *doc;
- fz_device *dev = NULL;
- pdf_obj *res = NULL;
- fz_buffer *contents = NULL;
- /* Convert fitz-space mediabox to pdf-space bbox */
- fz_rect mediabox = fz_bound_display_list(ctx, list);
- fz_matrix transform = { 1, 0, 0, -1, -mediabox.x0, mediabox.y1 };
- fz_rect bbox = fz_transform_rect(mediabox, transform);
- fz_var(dev);
- fz_var(contents);
- fz_var(res);
- begin_annot_op(ctx, annot, "Set appearance stream");
- doc = annot->page->doc;
- fz_try(ctx)
- {
- res = pdf_new_dict(ctx, doc, 1);
- contents = fz_new_buffer(ctx, 0);
- dev = pdf_new_pdf_device(ctx, doc, transform, res, contents);
- fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);
- fz_close_device(ctx, dev);
- fz_drop_device(ctx, dev);
- dev = NULL;
- pdf_set_annot_appearance(ctx, annot, appearance, state, ctm, bbox, res, contents);
- end_annot_op(ctx, annot);
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- fz_drop_buffer(ctx, contents);
- pdf_drop_obj(ctx, res);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- }
- static pdf_obj *stamp_subtypes[] = {
- PDF_NAME(Stamp),
- NULL,
- };
- pdf_obj *
- pdf_annot_stamp_image_obj(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *obj, *imgobj = NULL;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- obj = pdf_dict_getp(ctx, annot->obj, "AP/N/Resources/XObject");
- if (pdf_dict_len(ctx, obj) == 1)
- {
- obj = pdf_dict_get_val(ctx, obj, 0);
- if (pdf_is_image_stream(ctx, obj))
- imgobj = obj;
- }
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return imgobj;
- }
- void pdf_set_annot_stamp_image_obj(fz_context *ctx, pdf_annot *annot, pdf_obj *ref)
- {
- begin_annot_op(ctx, annot, "Set stamp image");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(Stamp), stamp_subtypes);
- pdf_dict_del(ctx, annot->obj, PDF_NAME(AP));
- pdf_dict_putp(ctx, annot->obj, "AP/N/Resources/XObject/I", ref);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- void pdf_set_annot_stamp_image(fz_context *ctx, pdf_annot *annot, fz_image *img)
- {
- pdf_obj *ref = pdf_add_image(ctx, annot->page->doc, img);
- fz_try(ctx)
- pdf_set_annot_stamp_image_obj(ctx, annot, ref);
- fz_always(ctx)
- pdf_drop_obj(ctx, ref);
- fz_catch(ctx)
- fz_rethrow(ctx);
- }
- static pdf_obj *filespec_subtypes[] = {
- PDF_NAME(FileAttachment),
- NULL,
- };
- int
- pdf_annot_has_filespec(fz_context *ctx, pdf_annot *annot)
- {
- return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(FS), filespec_subtypes);
- }
- pdf_obj *
- pdf_annot_filespec(fz_context *ctx, pdf_annot *annot)
- {
- pdf_obj *filespec;
- pdf_annot_push_local_xref(ctx, annot);
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(FS), filespec_subtypes);
- filespec = pdf_dict_get(ctx, annot->obj, PDF_NAME(FS));
- }
- fz_always(ctx)
- pdf_annot_pop_local_xref(ctx, annot);
- fz_catch(ctx)
- fz_rethrow(ctx);
- return filespec;
- }
- void
- pdf_set_annot_filespec(fz_context *ctx, pdf_annot *annot, pdf_obj *fs)
- {
- if (fs != PDF_NULL && !pdf_is_embedded_file(ctx, fs))
- fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot set non-filespec as annotation filespec");
- begin_annot_op(ctx, annot, "Set filespec");
- fz_try(ctx)
- {
- check_allowed_subtypes(ctx, annot, PDF_NAME(M), filespec_subtypes);
- pdf_dict_put(ctx, pdf_annot_obj(ctx, annot), PDF_NAME(FS), fs);
- end_annot_op(ctx, annot);
- }
- fz_catch(ctx)
- {
- abandon_annot_op(ctx, annot);
- fz_rethrow(ctx);
- }
- pdf_dirty_annot(ctx, annot);
- }
- int
- pdf_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot)
- {
- return annot->hidden_editing;
- }
- void
- pdf_set_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot, int hidden)
- {
- annot->hidden_editing = hidden;
- }
|