| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793 |
- /*
- * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Chris Wilson.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
- #include "config.h"
- /* TODO real path type */
- #include "cairo-script-private.h"
- #if CAIRO_HAS_SCRIPT_SURFACE
- #include "cairo-script.h"
- #endif
- #include <stdio.h> /* snprintf */
- #include <stdlib.h> /* mkstemp */
- #include <string.h>
- #ifdef _MSC_VER
- #define _USE_MATH_DEFINES /* for M_LN2, M_PI and M_SQRT2 on win32 */
- #define snprintf _snprintf
- #endif
- #include <math.h>
- #include <limits.h> /* INT_MAX */
- #include <assert.h>
- #if HAVE_ZLIB
- #include <zlib.h>
- #endif
- #if HAVE_LZO
- #include <lzo/lzo2a.h>
- #endif
- #ifdef HAVE_MMAP
- # ifdef HAVE_UNISTD_H
- # include <sys/mman.h>
- # include <unistd.h>
- # else
- # undef HAVE_MMAP
- # endif
- #endif
- typedef struct _csi_proxy {
- csi_t *ctx;
- void *ptr;
- csi_dictionary_t *dictionary;
- csi_destroy_func_t destroy_func;
- void *destroy_data;
- } csi_proxy_t;
- typedef struct _csi_blob {
- csi_list_t list;
- unsigned long hash;
- uint8_t *bytes;
- unsigned int len;
- } csi_blob_t;
- static const cairo_user_data_key_t _csi_proxy_key;
- static const cairo_user_data_key_t _csi_blob_key;
- enum mime_type {
- MIME_TYPE_NONE = 0,
- MIME_TYPE_PNG
- };
- #define check(CNT) do {\
- if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \
- return _csi_error (CSI_STATUS_INVALID_SCRIPT); \
- } while (0)
- #define pop(CNT) _csi_pop_ostack (ctx, (CNT))
- #define push(OBJ) _csi_push_ostack (ctx, (OBJ))
- static csi_proxy_t *
- _csi_proxy_create (csi_t *ctx,
- void *ptr,
- csi_dictionary_t *dictionary,
- csi_destroy_func_t destroy_func,
- void *destroy_data)
- {
- csi_proxy_t *proxy;
- proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t));
- if (proxy == NULL)
- return NULL;
- proxy->ctx = cairo_script_interpreter_reference (ctx);
- proxy->ptr = ptr;
- proxy->destroy_func = destroy_func;
- proxy->destroy_data = destroy_data;
- proxy->dictionary = dictionary;
- if (dictionary != NULL)
- dictionary->base.ref++;
- return proxy;
- }
- static void
- _csi_proxy_destroy (void *closure)
- {
- csi_proxy_t *proxy = closure;
- csi_t *ctx = proxy->ctx;
- /* XXX this doesn't work because user_data_destroy is called too late.
- * Considering another hook into the (cairo internal) object system.
- */
- if (proxy->destroy_func != NULL)
- proxy->destroy_func (proxy->destroy_data, proxy->ptr);
- if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0)
- csi_dictionary_free (ctx, proxy->dictionary);
- _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t));
- cairo_script_interpreter_destroy (ctx);
- }
- static void
- _csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len)
- {
- unsigned long hash = blob->hash;
- /* very simple! */
- while (len--) {
- unsigned long c = *data++;
- hash *= 33;
- hash ^= c;
- }
- blob->hash = hash;
- }
- static csi_boolean_t
- _csi_blob_equal (const csi_list_t *link, void *data)
- {
- csi_blob_t *A, *B;
- A = csi_container_of (link, csi_blob_t, list);
- B = data;
- if (A->len != B->len)
- return FALSE;
- if (A->hash != B->hash)
- return FALSE;
- return memcmp (A->bytes, B->bytes, A->len) == 0;
- }
- static void
- _csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len)
- {
- blob->hash = 5381;
- blob->len = len;
- blob->bytes = bytes;
- }
- static csi_list_t *
- _csi_list_unlink (csi_list_t *head, csi_list_t *link)
- {
- if (link->next != NULL)
- link->next->prev = link->prev;
- if (link->prev != NULL)
- link->prev->next = link->next;
- else
- head = link->next;
- return head;
- }
- static csi_list_t *
- _csi_list_prepend (csi_list_t *head, csi_list_t *link)
- {
- if (head != NULL)
- head->prev = link;
- link->next = head;
- link->prev = NULL;
- return link;
- }
- static csi_list_t *
- _csi_list_find (csi_list_t *head,
- csi_boolean_t (*predicate) (const csi_list_t *link, void *data),
- void *data)
- {
- while (head != NULL) {
- if (predicate (head, data))
- return head;
- head = head->next;
- }
- return NULL;
- }
- static csi_status_t
- _csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- *out = obj->datum.boolean;
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- *out = !! obj->datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- *out = obj->datum.real != 0.;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- *out = obj->datum.boolean;
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- *out = obj->datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- *out = obj->datum.real;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- *out = obj->datum.boolean;
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- *out = obj->datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- *out = obj->datum.real;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static double
- _csi_object_as_real (csi_object_t *obj)
- {
- int type;
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- return obj->datum.boolean;
- case CSI_OBJECT_TYPE_INTEGER:
- return obj->datum.integer;
- case CSI_OBJECT_TYPE_REAL:
- return obj->datum.real;
- default:
- return 0;
- }
- }
- static csi_status_t
- _csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.name;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.cr;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.font_face;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.pattern;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i,
- cairo_scaled_font_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely
- (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- *out = obj->datum.scaled_font;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- *out = cairo_get_target (obj->datum.cr);
- break;
- case CSI_OBJECT_TYPE_SURFACE:
- *out = obj->datum.surface;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.array;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (! csi_object_is_procedure (obj)))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.array;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely
- (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- *out = obj->datum.dictionary;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_MATRIX:
- *out = obj->datum.matrix->matrix;
- return CSI_STATUS_SUCCESS;
- case CSI_OBJECT_TYPE_ARRAY:
- if (obj->datum.array->stack.len == 6) {
- cairo_matrix_init (out,
- csi_number_get_value (&obj->datum.array->stack.objects[0]),
- csi_number_get_value (&obj->datum.array->stack.objects[1]),
- csi_number_get_value (&obj->datum.array->stack.objects[2]),
- csi_number_get_value (&obj->datum.array->stack.objects[3]),
- csi_number_get_value (&obj->datum.array->stack.objects[4]),
- csi_number_get_value (&obj->datum.array->stack.objects[5]));
- return CSI_STATUS_SUCCESS;
- }
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _csi_dictionary_get_integer (csi_t *ctx,
- csi_dictionary_t *dict,
- const char *name,
- csi_boolean_t optional,
- long *value)
- {
- csi_status_t status;
- csi_object_t key, obj;
- int type;
- status = csi_name_new_static (ctx, &key, name);
- if (_csi_unlikely (status))
- return status;
- if (optional && ! csi_dictionary_has (dict, key.datum.name))
- return CSI_STATUS_SUCCESS;
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- type = csi_object_get_type (&obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- *value = obj.datum.boolean;
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- *value = obj.datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- *value = obj.datum.real;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_dictionary_get_number (csi_t *ctx,
- csi_dictionary_t *dict,
- const char *name,
- csi_boolean_t optional,
- double *value)
- {
- csi_status_t status;
- csi_object_t key, obj;
- status = csi_name_new_static (ctx, &key, name);
- if (_csi_unlikely (status))
- return status;
- if (optional && ! csi_dictionary_has (dict, key.datum.name))
- return CSI_STATUS_SUCCESS;
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- *value = csi_number_get_value (&obj);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out)
- {
- csi_object_t *obj;
- obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- *out = obj->datum.string;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out)
- {
- csi_object_t *obj;
- int type;
- obj = _csi_peek_ostack (ctx, i);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_NAME:
- *out = (const char *) obj->datum.name;
- break;
- case CSI_OBJECT_TYPE_STRING:
- *out = obj->datum.string->string;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _do_cairo_op (csi_t *ctx, void (*op) (cairo_t *))
- {
- cairo_t *cr;
- csi_status_t status;
- check (1);
- status = _csi_ostack_get_context (ctx, 0, &cr);
- if (_csi_unlikely (status))
- return status;
- op (cr);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- end_dict_construction (csi_t *ctx)
- {
- csi_object_t obj;
- csi_dictionary_t *dict;
- csi_status_t status;
- status = csi_dictionary_new (ctx, &obj);
- if (_csi_unlikely (status))
- return status;
- dict = obj.datum.dictionary;
- do {
- csi_object_t *name, *value;
- check (1);
- value = _csi_peek_ostack (ctx, 0);
- if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) {
- pop (1);
- break;
- }
- check (2);
- name = _csi_peek_ostack (ctx, 1);
- if (_csi_unlikely
- (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- status = csi_dictionary_put (ctx, dict, name->datum.name, value);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- } while (TRUE);
- return push (&obj);
- }
- static csi_status_t
- end_array_construction (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- int len = 0;
- do {
- check (len + 1);
- if (csi_object_get_type (_csi_peek_ostack (ctx, len)) ==
- CSI_OBJECT_TYPE_MARK)
- {
- break;
- }
- len++;
- } while (TRUE);
- status = csi_array_new (ctx, len, &obj);
- if (_csi_unlikely (status))
- return status;
- if (len != 0) {
- csi_array_t *array;
- array = obj.datum.array;
- memcpy (array->stack.objects,
- _csi_peek_ostack (ctx, len - 1),
- sizeof (csi_object_t) * len);
- array->stack.len = len;
- }
- ctx->ostack.len -= len + 1;
- return push (&obj);
- }
- static csi_status_t
- _alpha (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double a;
- check (1);
- status = _csi_ostack_get_number (ctx, 0, &a);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a);
- return push (&obj);
- }
- static csi_status_t
- _add (csi_t *ctx)
- {
- csi_object_t *A;
- csi_object_t *B;
- csi_object_type_t type_a, type_b;
- check (2);
- B = _csi_peek_ostack (ctx, 0);
- A = _csi_peek_ostack (ctx, 1);
- type_a = csi_object_get_type (A);
- if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
- type_a == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- type_b = csi_object_get_type (B);
- if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
- type_b == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- if (type_a == CSI_OBJECT_TYPE_REAL &&
- type_b == CSI_OBJECT_TYPE_REAL)
- {
- return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real);
- }
- else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
- type_b == CSI_OBJECT_TYPE_INTEGER)
- {
- return _csi_push_ostack_integer (ctx,
- A->datum.integer + B->datum.integer);
- }
- else
- {
- double v;
- if (type_a == CSI_OBJECT_TYPE_REAL)
- v = A->datum.real;
- else
- v = A->datum.integer;
- if (type_b == CSI_OBJECT_TYPE_REAL)
- v += B->datum.real;
- else
- v += B->datum.integer;
- return _csi_push_ostack_real (ctx, v);
- }
- }
- static csi_status_t
- _add_color_stop (csi_t *ctx)
- {
- csi_status_t status;
- double offset, r, g, b, a;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- check (6);
- status = _csi_ostack_get_number (ctx, 0, &a);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &offset);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_pattern (ctx, 5, &pattern);
- if (_csi_unlikely (status))
- return status;
- cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a);
- pop (5);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _and (csi_t *ctx)
- {
- csi_object_t *a, *b;
- int type;
- check (2);
- a = _csi_peek_ostack (ctx, 0);
- b = _csi_peek_ostack (ctx, 1);
- if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- pop (2);
- type = csi_object_get_type (a);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- return _csi_push_ostack_integer (ctx,
- a->datum.integer & b->datum.integer);
- case CSI_OBJECT_TYPE_BOOLEAN:
- return _csi_push_ostack_boolean (ctx,
- a->datum.boolean & b->datum.boolean);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _arc (csi_t *ctx)
- {
- csi_status_t status;
- double x, y, r;
- double theta1, theta2;
- cairo_t *cr;
- check (6);
- status = _csi_ostack_get_number (ctx, 0, &theta2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &theta1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 5, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX handle path object */
- cairo_arc (cr, x, y, r, theta1, theta2);
- pop (5);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _arc_negative (csi_t *ctx)
- {
- csi_status_t status;
- double x, y, r;
- double theta1, theta2;
- cairo_t *cr;
- check (6);
- status = _csi_ostack_get_number (ctx, 0, &theta2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &theta1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 5, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX handle path object */
- cairo_arc_negative (cr, x, y, r, theta1, theta2);
- pop (5);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _array (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- status = csi_array_new (ctx, 0, &obj);
- if (_csi_unlikely (status))
- return status;
- return push (&obj);
- }
- static csi_status_t
- _bind_substitute (csi_t *ctx, csi_array_t *array)
- {
- csi_status_t status;
- csi_integer_t i, n;
- csi_dictionary_t *dict;
- /* perform operator substitution on the executable array (procedure) */
- dict = ctx->dstack.objects[0].datum.dictionary;
- n = array->stack.len;
- for (i = 0; i < n; i++) {
- csi_object_t *obj = &array->stack.objects[i];
- if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) {
- csi_dictionary_entry_t *entry;
- entry = _csi_hash_table_lookup (&dict->hash_table,
- (csi_hash_entry_t *)
- &obj->datum.name);
- if (entry != NULL)
- *obj = entry->value;
- } else if (csi_object_is_procedure (obj)) {
- status = _bind_substitute (ctx, obj->datum.array);
- if (_csi_unlikely (status))
- return status;
- }
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _idiom_substitute (csi_t *ctx, csi_array_t *array)
- {
- #if 0
- csi_status_t status;
- csi_integer_t i, j;
- /* XXX substring search, build array once then search for
- * longest matching idiom, repeat. */
- /* scan the top-most array for sequences we can pre-compile */
- /* now recurse for subroutines */
- j = array->stack.len;
- for (i = 0; i < j; i++) {
- csi_object_t *obj = &array->stack.objects[i];
- if (csi_object_is_procedure (obj)) {
- status = _idiom_substitute (ctx, obj->datum.array);
- if (_csi_unlikely (_cairo_is_error (status))
- return status;
- }
- }
- #endif
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _bind (csi_t *ctx)
- {
- csi_array_t *array;
- csi_status_t status;
- check (1);
- status = _csi_ostack_get_procedure (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = _bind_substitute (ctx, array);
- if (_csi_unlikely (status))
- return status;
- status = _idiom_substitute (ctx, array);
- if (_csi_unlikely (status))
- return status;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _bitshift (csi_t *ctx)
- {
- long v, shift;
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &shift);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &v);
- if (_csi_unlikely (status))
- return status;
- if (shift < 0) {
- shift = -shift;
- v >>= shift;
- } else
- v <<= shift;
- pop (1);
- _csi_peek_ostack (ctx, 0)->datum.integer = v;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _clip (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_clip);
- }
- static csi_status_t
- _clip_preserve (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_clip_preserve);
- }
- static csi_status_t
- _close_path (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_close_path);
- }
- static csi_status_t
- _context (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- cairo_surface_t *surface;
- cairo_t *cr;
- csi_context_create_func_t hook;
- csi_proxy_t *proxy;
- check (1);
- status = _csi_ostack_get_surface (ctx, 0, &surface);
- if (_csi_unlikely (status))
- return status;
- hook = ctx->hooks.context_create;
- if (hook != NULL)
- cr = hook (ctx->hooks.closure, surface);
- else
- cr = cairo_create (surface);
- proxy = _csi_proxy_create (ctx, cr, NULL,
- ctx->hooks.context_destroy,
- ctx->hooks.closure);
- if (_csi_unlikely (proxy == NULL)) {
- cairo_destroy (cr);
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- status = cairo_set_user_data (cr, &_csi_proxy_key,
- proxy, _csi_proxy_destroy);
- if (_csi_unlikely (status)) {
- _csi_proxy_destroy (proxy);
- cairo_destroy (cr);
- return status;
- }
- pop (1);
- obj.type = CSI_OBJECT_TYPE_CONTEXT;
- obj.datum.cr = cr;
- return push (&obj);
- }
- static csi_status_t
- _copy (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = csi_object_reference (_csi_peek_ostack (ctx, 0));
- pop (1);
- type = csi_object_get_type (obj);
- switch (type) {
- /*XXX array, string, dictionary, etc */
- case CSI_OBJECT_TYPE_INTEGER:
- {
- long i, n;
- n = obj->datum.integer;
- if (_csi_unlikely (n < 0))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- check (n);
- for (i = n; i--; ) {
- csi_status_t status;
- status = _csi_push_ostack_copy (ctx,
- _csi_peek_ostack (ctx, n-1));
- if (_csi_unlikely (status))
- return status;
- }
- break;
- }
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _copy_page (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_copy_page (obj->datum.cr);
- if (ctx->hooks.copy_page != NULL)
- ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
- break;
- case CSI_OBJECT_TYPE_SURFACE:
- cairo_surface_copy_page (obj->datum.surface);
- /* XXX hook? */
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _curve_to (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- int type;
- double x1, y1;
- double x2, y2;
- double x3, y3;
- check (7);
- status = _csi_ostack_get_number (ctx, 0, &y3);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x3);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &y2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &x2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &y1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 5, &x1);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 6);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_mesh_pattern_curve_to (obj->datum.pattern,
- x1, y1, x2, y2, x3, y3);
- break;
- /* XXX handle path object */
- }
- pop (6);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _cvi (csi_t *ctx)
- {
- csi_object_t *val, obj;
- int type;
- check (1);
- val = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (val);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- return CSI_STATUS_SUCCESS;
- case CSI_OBJECT_TYPE_REAL:
- pop (1);
- return _csi_push_ostack_integer (ctx, val->datum.real);
- case CSI_OBJECT_TYPE_STRING:
- if (! _csi_parse_number (&obj,
- val->datum.string->string,
- val->datum.string->len))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_INTEGER)
- return push (&obj);
- else
- return _csi_push_ostack_integer (ctx, obj.datum.real);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _cvr (csi_t *ctx)
- {
- csi_object_t *val, obj;
- int type;
- check (1);
- val = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (val);
- switch (type) {
- case CSI_OBJECT_TYPE_REAL:
- return CSI_STATUS_SUCCESS;
- case CSI_OBJECT_TYPE_INTEGER:
- pop (1);
- return _csi_push_ostack_real (ctx, val->datum.integer);
- case CSI_OBJECT_TYPE_STRING:
- if (! _csi_parse_number (&obj,
- val->datum.string->string,
- val->datum.string->len))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_REAL)
- return push (&obj);
- else
- return _csi_push_ostack_real (ctx, obj.datum.integer);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _def (csi_t *ctx)
- {
- csi_name_t name = 0; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_name (ctx, 1, &name);
- if (_csi_unlikely (status))
- return status;
- status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0));
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _dict (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- status = csi_dictionary_new (ctx, &obj);
- if (_csi_unlikely (status))
- return status;
- return push (&obj);
- }
- static csi_status_t
- _div (csi_t *ctx)
- {
- csi_object_t *A;
- csi_object_t *B;
- csi_object_type_t type_a, type_b;
- check (2);
- B = _csi_peek_ostack (ctx, 0);
- A = _csi_peek_ostack (ctx, 1);
- type_a = csi_object_get_type (A);
- if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
- type_a == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- type_b = csi_object_get_type (B);
- if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
- type_b == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- if (type_a == CSI_OBJECT_TYPE_REAL &&
- type_b == CSI_OBJECT_TYPE_REAL)
- {
- return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real);
- }
- else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
- type_b == CSI_OBJECT_TYPE_INTEGER)
- {
- return _csi_push_ostack_integer (ctx,
- A->datum.integer / B->datum.integer);
- }
- else
- {
- double v;
- if (type_a == CSI_OBJECT_TYPE_REAL)
- v = A->datum.real;
- else
- v = A->datum.integer;
- if (type_b == CSI_OBJECT_TYPE_REAL)
- v /= B->datum.real;
- else
- v /= B->datum.integer;
- return _csi_push_ostack_real (ctx, v);
- }
- }
- static csi_status_t
- _duplicate (csi_t *ctx)
- {
- check (1);
- return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0));
- }
- static csi_status_t
- _eq (csi_t *ctx)
- {
- csi_object_t *a, *b;
- csi_boolean_t v;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- v = csi_object_eq (a, b);
- pop (2);
- return _csi_push_ostack_boolean (ctx, v);
- }
- static csi_status_t
- _exch (csi_t *ctx)
- {
- return _csi_stack_exch (&ctx->ostack);
- }
- static csi_status_t
- _false (csi_t *ctx)
- {
- return _csi_push_ostack_boolean (ctx, FALSE);
- }
- static csi_status_t
- _fill (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_fill);
- }
- static csi_status_t
- _fill_preserve (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_fill_preserve);
- }
- static csi_status_t
- _filter (csi_t *ctx)
- {
- csi_object_t *src;
- csi_dictionary_t *dict = NULL;
- csi_status_t status;
- const char *name = NULL; /* silence the compiler */
- const struct filters {
- const char *name;
- csi_status_t (*constructor) (csi_t *t,
- csi_object_t *,
- csi_dictionary_t *,
- csi_object_t *);
- } filters[] = {
- { "ascii85", csi_file_new_ascii85_decode },
- #if HAVE_ZLIB
- { "deflate", csi_file_new_deflate_decode },
- #endif
- #if 0
- { "lzw", csi_file_new_lzw_decode },
- #endif
- { NULL, NULL }
- }, *filter;
- int cnt;
- check (2);
- status = _csi_ostack_get_string_constant (ctx, 0, &name);
- if (_csi_unlikely (status))
- return status;
- src = _csi_peek_ostack (ctx, 1);
- cnt = 2;
- if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) {
- dict = src->datum.dictionary;
- check (3);
- src = _csi_peek_ostack (ctx, 2);
- cnt = 3;
- }
- for (filter = filters; filter->name != NULL; filter++) {
- if (strcmp (name, filter->name) == 0) {
- csi_object_t file;
- status = filter->constructor (ctx, &file, dict, src);
- if (_csi_unlikely (status))
- return status;
- pop (cnt);
- return push (&file);
- }
- }
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- static cairo_status_t
- _type3_init (cairo_scaled_font_t *scaled_font,
- cairo_t *cr,
- cairo_font_extents_t *metrics)
- {
- cairo_font_face_t *face;
- csi_proxy_t *proxy;
- csi_t *ctx;
- csi_dictionary_t *font;
- csi_object_t key;
- csi_object_t obj;
- csi_array_t *array;
- csi_status_t status;
- face = cairo_scaled_font_get_font_face (scaled_font);
- proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
- if (_csi_unlikely (proxy == NULL))
- return CAIRO_STATUS_NO_MEMORY;
- ctx = proxy->ctx;
- font = proxy->dictionary;
- status = csi_name_new_static (ctx, &key, "metrics");
- if (_csi_unlikely (status))
- return CAIRO_STATUS_NO_MEMORY;
- if (! csi_dictionary_has (font, key.datum.name))
- return CAIRO_STATUS_SUCCESS;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)
- return CAIRO_STATUS_USER_FONT_ERROR;
- array = obj.datum.array;
- if (array->stack.len != 5)
- return CAIRO_STATUS_USER_FONT_ERROR;
- metrics->ascent = csi_number_get_value (&array->stack.objects[0]);
- metrics->descent = csi_number_get_value (&array->stack.objects[1]);
- metrics->height = csi_number_get_value (&array->stack.objects[2]);
- metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]);
- metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]);
- return CAIRO_STATUS_SUCCESS;
- }
- static cairo_status_t
- _type3_lookup (cairo_scaled_font_t *scaled_font,
- unsigned long unicode,
- unsigned long *glyph)
- {
- cairo_font_face_t *face;
- csi_proxy_t *proxy;
- csi_t *ctx;
- csi_dictionary_t *font;
- csi_object_t obj, key;
- csi_array_t *array;
- char buf[12];
- csi_integer_t i;
- cairo_status_t status;
- face = cairo_scaled_font_get_font_face (scaled_font);
- proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
- if (_csi_unlikely (proxy == NULL))
- return CAIRO_STATUS_USER_FONT_ERROR;
- ctx = proxy->ctx;
- font = proxy->dictionary;
- status = csi_name_new_static (ctx, &key, "encoding");
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- if (! csi_dictionary_has (font, key.datum.name)) {
- *glyph = unicode;
- return CAIRO_STATUS_SUCCESS;
- }
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
- return CAIRO_STATUS_USER_FONT_ERROR;
- snprintf (buf, sizeof (buf), "uni%04lu", unicode);
- array = obj.datum.array;
- for (i = 0; i < array->stack.len; i++) {
- csi_object_t *name;
- name = &array->stack.objects[i];
- if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)
- continue;
- if (strcmp ((char *) name->datum.name, buf) == 0) {
- *glyph = i;
- return CAIRO_STATUS_SUCCESS;
- }
- }
- return CAIRO_STATUS_USER_FONT_ERROR;
- }
- static cairo_status_t
- _type3_render (cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
- cairo_t *cr,
- cairo_text_extents_t *metrics)
- {
- cairo_font_face_t *face;
- csi_proxy_t *proxy;
- csi_t *ctx;
- csi_dictionary_t *font;
- csi_array_t *glyphs;
- csi_object_t *glyph;
- csi_object_t key;
- csi_object_t obj;
- csi_object_t render;
- csi_status_t status;
- face = cairo_scaled_font_get_font_face (scaled_font);
- proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
- if (_csi_unlikely (proxy == NULL))
- return CAIRO_STATUS_USER_FONT_ERROR;
- ctx = proxy->ctx;
- font = proxy->dictionary;
- status = csi_name_new_static (ctx, &key, "glyphs");
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
- return CAIRO_STATUS_USER_FONT_ERROR;
- glyphs = obj.datum.array;
- glyph = &glyphs->stack.objects[glyph_index];
- if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL)
- return CAIRO_STATUS_SUCCESS; /* .notdef */
- if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY))
- return CAIRO_STATUS_USER_FONT_ERROR;
- status = csi_name_new_static (ctx, &key, "metrics");
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- font = glyph->datum.dictionary;
- if (csi_dictionary_has (font, key.datum.name)) {
- csi_array_t *array;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- if (_csi_unlikely (csi_object_get_type (&obj) !=
- CSI_OBJECT_TYPE_ARRAY))
- return CAIRO_STATUS_USER_FONT_ERROR;
- array = obj.datum.array;
- if (_csi_unlikely (array->stack.len != 6))
- return CAIRO_STATUS_USER_FONT_ERROR;
- metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]);
- metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]);
- metrics->width = csi_number_get_value (&array->stack.objects[2]);
- metrics->height = csi_number_get_value (&array->stack.objects[3]);
- metrics->x_advance = csi_number_get_value (&array->stack.objects[4]);
- metrics->y_advance = csi_number_get_value (&array->stack.objects[5]);
- }
- status = csi_name_new_static (ctx, &key, "render");
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- status = csi_dictionary_get (ctx, font, key.datum.name, &render);
- if (_csi_unlikely (status))
- return CAIRO_STATUS_USER_FONT_ERROR;
- if (_csi_unlikely (! csi_object_is_procedure (&render)))
- return CAIRO_STATUS_USER_FONT_ERROR;
- obj.type = CSI_OBJECT_TYPE_CONTEXT;
- obj.datum.cr = cairo_reference (cr);
- status = push (&obj);
- if (_csi_unlikely (status)) {
- cairo_destroy (cr);
- return CAIRO_STATUS_USER_FONT_ERROR;
- }
- status = csi_object_execute (ctx, &render);
- pop (1);
- return status ? CAIRO_STATUS_USER_FONT_ERROR : CAIRO_STATUS_SUCCESS;
- }
- static csi_status_t
- _font_type3 (csi_t *ctx,
- csi_dictionary_t *font,
- cairo_font_face_t **font_face_out)
- {
- cairo_font_face_t *font_face;
- font_face = cairo_user_font_face_create ();
- cairo_user_font_face_set_init_func (font_face, _type3_init);
- cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup);
- cairo_user_font_face_set_render_glyph_func (font_face, _type3_render);
- *font_face_out = font_face;
- return CSI_STATUS_SUCCESS;
- }
- #if CAIRO_HAS_FT_FONT
- #include <cairo-ft.h>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- static FT_Library _ft_lib;
- struct _ft_face_data {
- csi_t *ctx;
- csi_blob_t blob;
- FT_Face face;
- csi_string_t *source;
- void *bytes;
- cairo_font_face_t *font_face;
- };
- static void
- _ft_done_face (void *closure)
- {
- struct _ft_face_data *data = closure;
- csi_t *ctx;
- ctx = data->ctx;
- if (data->face != NULL)
- FT_Done_Face (data->face);
- ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list);
- if (data->source != NULL) {
- if (--data->source->base.ref == 0)
- csi_string_free (ctx, data->source);
- } else {
- #ifdef HAVE_MMAP
- munmap (data->blob.bytes, data->blob.len);
- #endif
- }
- if (data->bytes != NULL)
- _csi_free (ctx, data->bytes);
- _csi_slab_free (ctx, data, sizeof (*data));
- cairo_script_interpreter_destroy (ctx);
- }
- struct mmap_vec {
- const uint8_t *bytes;
- size_t num_bytes;
- };
- #ifdef HAVE_MMAP
- /* manual form of swapping for swapless systems like tiny */
- static void *
- _mmap_bytes (const struct mmap_vec *vec, int count)
- {
- char template[] = "/tmp/csi-font.XXXXXX";
- void *ptr;
- int fd;
- int num_bytes;
- fd = mkstemp (template);
- if (fd == -1)
- return MAP_FAILED;
- unlink (template);
- num_bytes = 0;
- while (count--) {
- const uint8_t *bytes = vec->bytes;
- size_t len = vec->num_bytes;
- while (len) {
- int ret = write (fd, bytes, len);
- if (ret < 0) {
- close (fd);
- return MAP_FAILED;
- }
- len -= ret;
- bytes += ret;
- }
- num_bytes += vec->num_bytes;
- vec++;
- }
- ptr = mmap (NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0);
- close (fd);
- return ptr;
- }
- #endif
- static void *
- inflate_string (csi_t *ctx, csi_string_t *src)
- {
- uLongf len;
- uint8_t *bytes;
- len = src->deflate;
- bytes = _csi_alloc (ctx, len + 1);
- if (bytes == NULL)
- return NULL;
- switch (src->method) {
- default:
- case NONE:
- free (bytes);
- return NULL;
- case ZLIB:
- #if HAVE_ZLIB
- if (uncompress ((Bytef *) bytes, &len,
- (Bytef *) src->string, src->len) != Z_OK)
- #endif
- {
- _csi_free (ctx, bytes);
- return NULL;
- }
- break;
- case LZO:
- #if HAVE_LZO
- if (lzo2a_decompress ((Bytef *) src->string, src->len,
- (Bytef *) bytes, &len,
- NULL))
- #endif
- {
- _csi_free (ctx, bytes);
- return NULL;
- }
- break;
- }
- bytes[len] = '\0';
- return bytes;
- }
- static csi_status_t
- _ft_create_for_source (csi_t *ctx,
- csi_string_t *source,
- int index, int load_flags,
- cairo_font_face_t **font_face_out)
- {
- csi_blob_t tmpl;
- struct _ft_face_data *data;
- csi_list_t *link;
- FT_Error err;
- cairo_font_face_t *font_face;
- csi_status_t status;
- struct mmap_vec vec[2];
- int vec_count;
- void *bytes;
- int len;
- /* check for an existing FT_Face (kept alive by the font cache) */
- /* XXX index/flags */
- _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len);
- _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t));
- link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
- if (link) {
- if (--source->base.ref == 0)
- csi_string_free (ctx, source);
- data = csi_container_of (link, struct _ft_face_data, blob.list);
- *font_face_out = cairo_font_face_reference (data->font_face);
- return CSI_STATUS_SUCCESS;
- }
- /* no existing font_face, create new FT_Face */
- if (_ft_lib == NULL) {
- err = FT_Init_FreeType (&_ft_lib);
- if (_csi_unlikely (err != FT_Err_Ok))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- data = _csi_slab_alloc (ctx, sizeof (*data));
- data->bytes = NULL;
- data->source = source;
- vec[0].bytes = tmpl.bytes;
- vec[0].num_bytes = tmpl.len;
- if (source->deflate) {
- len = source->deflate;
- bytes = inflate_string (ctx, source);
- if (_csi_unlikely (bytes == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- vec[1].bytes = bytes;
- vec[1].num_bytes = len;
- data->bytes = bytes;
- vec_count = 2;
- } else {
- bytes = tmpl.bytes;
- len = tmpl.len;
- vec_count = 1;
- }
- data->face = NULL;
- ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
- data->ctx = cairo_script_interpreter_reference (ctx);
- data->blob.hash = tmpl.hash;
- data->blob.len = tmpl.len;
- #ifdef HAVE_MMAP
- data->blob.bytes = _mmap_bytes (vec, vec_count);
- if (data->blob.bytes != MAP_FAILED) {
- if (--source->base.ref == 0)
- csi_string_free (ctx, source);
- if (source->deflate) {
- _csi_free (ctx, bytes);
- bytes = data->blob.bytes + vec[0].num_bytes;
- } else
- bytes = data->blob.bytes;
- data->source = NULL;
- data->bytes = NULL;
- } else {
- data->blob.bytes = tmpl.bytes;
- }
- #else
- data->blob.bytes = tmpl.bytes;
- #endif
- err = FT_New_Memory_Face (_ft_lib,
- bytes, len,
- index,
- &data->face);
- if (_csi_unlikely (err != FT_Err_Ok)) {
- _ft_done_face (data);
- if (err == FT_Err_Out_Of_Memory)
- return _csi_error (CSI_STATUS_NO_MEMORY);
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- font_face = cairo_ft_font_face_create_for_ft_face (data->face, load_flags);
- status = cairo_font_face_set_user_data (font_face,
- &_csi_blob_key,
- data, _ft_done_face);
- if (_csi_unlikely (status)) {
- _ft_done_face (data);
- cairo_font_face_destroy (font_face);
- return status;
- }
- data->font_face = font_face;
- *font_face_out = font_face;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _ft_create_for_pattern (csi_t *ctx,
- csi_string_t *string,
- cairo_font_face_t **font_face_out)
- {
- #if CAIRO_HAS_FC_FONT
- csi_blob_t tmpl;
- struct _ft_face_data *data;
- csi_list_t *link;
- cairo_font_face_t *font_face;
- FcPattern *pattern, *resolved;
- csi_status_t status;
- struct mmap_vec vec;
- void *bytes;
- _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len);
- _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t));
- link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
- if (link) {
- if (--string->base.ref == 0)
- csi_string_free (ctx, string);
- data = csi_container_of (link, struct _ft_face_data, blob.list);
- *font_face_out = cairo_font_face_reference (data->font_face);
- return CSI_STATUS_SUCCESS;
- }
- if (string->deflate) {
- bytes = inflate_string (ctx, string);
- if (_csi_unlikely (bytes == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else {
- bytes = tmpl.bytes;
- }
- pattern = FcNameParse (bytes);
- if (!pattern)
- {
- /* Fontconfig's representation of charset changed mid 2014;
- * We used to record charset before that. Remove everything
- * after charset if that's present, and try again. */
- char *s = strstr ((char *) bytes, ":charset=");
- if (s)
- {
- *s = '\0';
- pattern = FcNameParse (bytes);
- }
- }
- if (bytes != tmpl.bytes)
- _csi_free (ctx, bytes);
- retry:
- resolved = pattern;
- if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) {
- /* prior to 1.9, you needed to pass a resolved pattern */
- resolved = FcFontMatch (NULL, pattern, NULL);
- if (_csi_unlikely (resolved == NULL)) {
- FcPatternDestroy (pattern);
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- }
- font_face = cairo_ft_font_face_create_for_pattern (resolved);
- if (resolved != pattern)
- FcPatternDestroy (resolved);
- if (cairo_font_face_status (font_face)) {
- char *filename = NULL;
- /* Try a manual fallback process by eliminating specific requests */
- if (FcPatternGetString (pattern,
- FC_FILE, 0,
- (FcChar8 **) &filename) == FcResultMatch) {
- FcPatternDel (pattern, FC_FILE);
- goto retry;
- }
- }
- FcPatternDestroy (pattern);
- data = _csi_slab_alloc (ctx, sizeof (*data));
- ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
- data->ctx = cairo_script_interpreter_reference (ctx);
- data->blob.hash = tmpl.hash;
- data->blob.len = tmpl.len;
- data->bytes = NULL;
- data->face = NULL;
- #ifdef HAVE_MMAP
- vec.bytes = tmpl.bytes;
- vec.num_bytes = tmpl.len;
- data->blob.bytes = _mmap_bytes (&vec, 1);
- if (data->blob.bytes != MAP_FAILED) {
- data->source = NULL;
- if (--string->base.ref == 0)
- csi_string_free (ctx, string);
- } else {
- data->blob.bytes = tmpl.bytes;
- data->source = string;
- }
- #else
- data->blob.bytes = tmpl.bytes;
- data->source = string;
- #endif
- status = cairo_font_face_set_user_data (font_face,
- &_csi_blob_key,
- data, _ft_done_face);
- if (_csi_unlikely (status)) {
- _ft_done_face (data);
- cairo_font_face_destroy (font_face);
- return status;
- }
- data->font_face = font_face;
- *font_face_out = font_face;
- return CSI_STATUS_SUCCESS;
- #else
- if (--string->base.ref == 0)
- csi_string_free (ctx, string);
- return CSI_INT_STATUS_UNSUPPORTED;
- #endif
- }
- static csi_status_t
- _ft_type42_create (csi_t *ctx,
- csi_dictionary_t *font,
- cairo_font_face_t **font_face_out)
- {
- csi_object_t key;
- csi_status_t status;
- /* two basic sub-types, either an FcPattern or embedded font */
- status = csi_name_new_static (ctx, &key, "pattern");
- if (_csi_unlikely (status))
- return status;
- if (csi_dictionary_has (font, key.datum.name)) {
- csi_object_t obj;
- int type;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- type = csi_object_get_type (&obj);
- switch (type) {
- case CSI_OBJECT_TYPE_FILE:
- status = _csi_file_as_string (ctx, obj.datum.file, &obj);
- if (_csi_unlikely (status))
- return status;
- break;
- case CSI_OBJECT_TYPE_STRING:
- obj.datum.object->ref++;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return _ft_create_for_pattern (ctx,
- obj.datum.string,
- font_face_out);
- }
- status = csi_name_new_static (ctx, &key, "source");
- if (_csi_unlikely (status))
- return status;
- if (csi_dictionary_has (font, key.datum.name)) {
- csi_object_t obj;
- long index, flags;
- int type;
- index = 0;
- status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index);
- if (_csi_unlikely (status))
- return status;
- flags = 0;
- status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags);
- if (_csi_unlikely (status))
- return status;
- status = csi_name_new_static (ctx, &key, "source");
- if (_csi_unlikely (status))
- return status;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- type = csi_object_get_type (&obj);
- switch (type) {
- case CSI_OBJECT_TYPE_FILE:
- status = _csi_file_as_string (ctx, obj.datum.file, &obj);
- if (_csi_unlikely (status))
- return status;
- break;
- case CSI_OBJECT_TYPE_STRING:
- obj.datum.object->ref++;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return _ft_create_for_source (ctx, obj.datum.string,
- index, flags,
- font_face_out);
- }
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- #else
- #define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED
- #endif
- static char *
- _fc_strcpy (csi_t *ctx, const char *str)
- {
- char *ret;
- int len;
- ret = strchr (str, ':');
- if (ret != NULL)
- len = ret - str;
- else
- len = strlen (str);
- ret = _csi_alloc (ctx, len+1);
- if (_csi_unlikely (ret == NULL))
- return NULL;
- memcpy (ret, str, len);
- ret[len] = '\0';
- return ret;
- }
- static cairo_font_face_t *
- _select_font (const char *name)
- {
- cairo_surface_t *surface;
- cairo_font_face_t *face;
- cairo_t *cr;
- /* create a dummy context to choose a font */
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
- cr = cairo_create (surface);
- cairo_surface_destroy (surface);
- cairo_select_font_face (cr, name,
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_NORMAL);
- face = cairo_font_face_reference (cairo_get_font_face (cr));
- cairo_destroy (cr);
- return face;
- }
- static csi_status_t
- _ft_fallback_create_for_pattern (csi_t *ctx,
- csi_string_t *string,
- cairo_font_face_t **font_face_out)
- {
- char *str, *name;
- str = string->string;
- #if 0
- name = strstr (str, "fullname=");
- if (name != NULL)
- str = name + 9;
- #endif
- name = _fc_strcpy (ctx, str);
- if (_csi_unlikely (name == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- *font_face_out = _select_font (name);
- _csi_free (ctx, name);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _ft_type42_fallback_create (csi_t *ctx,
- csi_dictionary_t *font,
- cairo_font_face_t **font_face_out)
- {
- csi_object_t key;
- csi_status_t status;
- /* attempt to select a similar font */
- /* two basic sub-types, either an FcPattern or embedded font */
- status = csi_name_new_static (ctx, &key, "pattern");
- if (_csi_unlikely (status))
- return status;
- if (csi_dictionary_has (font, key.datum.name)) {
- csi_object_t obj;
- int type;
- status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- type = csi_object_get_type (&obj);
- switch (type) {
- case CSI_OBJECT_TYPE_FILE:
- status = _csi_file_as_string (ctx, obj.datum.file, &obj);
- if (_csi_unlikely (status))
- return status;
- break;
- case CSI_OBJECT_TYPE_STRING:
- obj.datum.object->ref++;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return _ft_fallback_create_for_pattern (ctx,
- obj.datum.string,
- font_face_out);
- }
- /* XXX: enable the trace to run */
- *font_face_out = _select_font ("Sans");
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face)
- {
- csi_status_t status;
- status = _ft_type42_create (ctx, font, font_face);
- if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED))
- return status;
- return _ft_type42_fallback_create (ctx, font, font_face);
- }
- static csi_status_t
- _font (csi_t *ctx)
- {
- csi_dictionary_t *font;
- csi_status_t status;
- cairo_font_face_t *font_face = NULL; /* silence the compiler */
- csi_proxy_t *proxy;
- csi_object_t obj;
- long type;
- check (1);
- status = _csi_ostack_get_dictionary (ctx, 0, &font);
- if (_csi_unlikely (status))
- return status;
- status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type);
- if (_csi_unlikely (status))
- return status;
- switch (type) {
- case 3:
- status = _font_type3 (ctx, font, &font_face);
- break;
- case 42:
- status = _font_type42 (ctx, font, &font_face);
- break;
- default:
- status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
- break;
- }
- if (_csi_unlikely (status))
- return status;
- /* transfer ownership of dictionary to cairo_font_face_t */
- proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL);
- if (_csi_unlikely (proxy == NULL)) {
- cairo_font_face_destroy (font_face);
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- status = cairo_font_face_set_user_data (font_face,
- &_csi_proxy_key,
- proxy, _csi_proxy_destroy);
- if (_csi_unlikely (status)) {
- _csi_proxy_destroy (proxy);
- cairo_font_face_destroy (font_face);
- return status;
- }
- obj.type = CSI_OBJECT_TYPE_FONT;
- obj.datum.font_face = font_face;
- pop (1);
- status = push (&obj);
- if (_csi_unlikely (status)) {
- cairo_font_face_destroy (font_face);
- return status;
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _for (csi_t *ctx)
- {
- csi_array_t *proc;
- csi_status_t status;
- long i, inc, limit;
- check (4);
- status = _csi_ostack_get_procedure (ctx, 0, &proc);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &limit);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 2, &inc);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 3, &i);
- if (_csi_unlikely (status))
- return status;
- proc->base.ref++;
- pop (4);
- for (; i <= limit; i += inc) {
- status = _csi_push_ostack_integer (ctx, i);
- if (_csi_unlikely (status))
- break;
- status = _csi_array_execute (ctx, proc);
- if (_csi_unlikely (status))
- break;
- }
- if (--proc->base.ref == 0)
- csi_array_free (ctx, proc);
- return status;
- }
- static csi_status_t
- _ge (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *a, *b;
- int cmp;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- status = csi_object_compare (a, b, &cmp);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return _csi_push_ostack_boolean (ctx, cmp >= 0);
- }
- static csi_status_t
- _proxy_get (csi_proxy_t *proxy,
- csi_name_t key)
- {
- csi_object_t obj;
- csi_status_t status;
- if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj);
- if (_csi_unlikely (status))
- return status;
- return _csi_push_ostack_copy (proxy->ctx, &obj);
- }
- static csi_status_t
- _context_get (csi_t *ctx,
- cairo_t *cr,
- csi_name_t key)
- {
- csi_status_t status;
- csi_object_t obj;
- if (strcmp ((char *) key, "current-point") == 0) {
- double x, y;
- cairo_get_current_point (cr, &x, &y);
- status = _csi_push_ostack_real (ctx, x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_push_ostack_real (ctx, y);
- if (_csi_unlikely (status))
- return status;
- return CSI_STATUS_SUCCESS;
- } else if (strcmp ((char *) key, "source") == 0) {
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr));
- } else if (strcmp ((char *) key, "target") == 0) {
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_reference (cairo_get_target (cr));
- } else if (strcmp ((char *) key, "group-target") == 0) {
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr));
- } else if (strcmp ((char *) key, "scaled-font") == 0) {
- obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
- obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr));
- } else if (strcmp ((char *) key, "font-face") == 0) {
- obj.type = CSI_OBJECT_TYPE_FONT;
- obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr));
- } else
- return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key);
- return push (&obj);
- }
- static csi_status_t
- _font_get (csi_t *ctx,
- cairo_font_face_t *font_face,
- csi_name_t key)
- {
- return _proxy_get (cairo_font_face_get_user_data (font_face,
- &_csi_proxy_key),
- key);
- }
- static csi_status_t
- _pattern_get (csi_t *ctx,
- cairo_pattern_t *pattern,
- csi_name_t key)
- {
- csi_status_t status;
- if (strcmp ((char *) key, "type") == 0)
- return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern));
- if (strcmp ((char *) key, "filter") == 0)
- return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern));
- if (strcmp ((char *) key, "extend") == 0)
- return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern));
- if (strcmp ((char *) key, "matrix") == 0) {
- csi_object_t obj;
- cairo_matrix_t m;
- cairo_pattern_get_matrix (pattern, &m);
- status = csi_matrix_new_from_matrix (ctx, &obj, &m);
- if (_csi_unlikely (status))
- return status;
- return push (&obj);
- }
- return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key),
- key);
- }
- static csi_status_t
- _scaled_font_get (csi_t *ctx,
- cairo_scaled_font_t *font,
- csi_name_t key)
- {
- return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key),
- key);
- }
- static csi_status_t
- _surface_get (csi_t *ctx,
- cairo_surface_t *surface,
- csi_name_t key)
- {
- if (strcmp ((char *) key, "type") == 0) {
- return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface));
- }
- if (strcmp ((char *) key, "content") == 0) {
- return _csi_push_ostack_integer (ctx,
- cairo_surface_get_content (surface));
- }
- return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key),
- key);
- }
- static csi_status_t
- _get (csi_t *ctx)
- {
- csi_object_t *key, *src, obj;
- csi_status_t status;
- int type;
- check (2);
- key = _csi_peek_ostack (ctx, 0);
- src = _csi_peek_ostack (ctx, 1);
- pop (1);
- type = csi_object_get_type (src);
- switch (type) {
- case CSI_OBJECT_TYPE_DICTIONARY:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = csi_dictionary_get (ctx,
- src->datum.dictionary,
- key->datum.name,
- &obj);
- break;
- case CSI_OBJECT_TYPE_ARRAY:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = csi_array_get (ctx,
- src->datum.array,
- key->datum.integer,
- &obj);
- break;
- #if 0
- case CSI_OBJECT_TYPE_STRING:
- status = csi_string_get (src, key, &obj);
- break;
- #endif
- case CSI_OBJECT_TYPE_CONTEXT:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- return _context_get (ctx, src->datum.cr, key->datum.name);
- case CSI_OBJECT_TYPE_FONT:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- return _font_get (ctx, src->datum.font_face, key->datum.name);
- case CSI_OBJECT_TYPE_PATTERN:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- return _pattern_get (ctx, src->datum.pattern, key->datum.name);
- case CSI_OBJECT_TYPE_SCALED_FONT:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name);
- case CSI_OBJECT_TYPE_SURFACE:
- if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- return _surface_get (ctx, src->datum.surface, key->datum.name);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- if (_csi_unlikely (status))
- return status;
- return _csi_push_ostack_copy (ctx, &obj);
- }
- struct glyph_advance_cache {
- csi_t *ctx;
- double glyph_advance[256][2];
- unsigned long have_glyph_advance[256];
- };
- static void
- glyph_advance_cache_destroy (void *closure)
- {
- struct glyph_advance_cache *cache = closure;
- _csi_free (cache->ctx, cache);
- }
- static int
- _glyph_string (csi_t *ctx,
- csi_array_t *array,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs)
- {
- struct glyph_advance_cache uncached;
- struct glyph_advance_cache *cache;
- csi_integer_t nglyphs, i, j;
- double x, y, dx;
- cairo_status_t status;
- if (cairo_scaled_font_status (scaled_font))
- return 0;
- cache = cairo_scaled_font_get_user_data (scaled_font,
- (cairo_user_data_key_t *) ctx);
- if (cache == NULL) {
- cache = _csi_alloc (ctx, sizeof (*cache));
- if (_csi_likely (cache != NULL)) {
- cache->ctx = ctx;
- memset (cache->have_glyph_advance, 0xff,
- sizeof (cache->have_glyph_advance));
- status = cairo_scaled_font_set_user_data (scaled_font,
- (cairo_user_data_key_t *) ctx,
- cache,
- glyph_advance_cache_destroy);
- if (_csi_unlikely (status)) {
- _csi_free (ctx, cache);
- cache = NULL;
- }
- }
- }
- if (_csi_unlikely (cache == NULL)) {
- cache = &uncached;
- cache->ctx = ctx;
- memset (cache->have_glyph_advance, 0xff,
- sizeof (cache->have_glyph_advance));
- }
- nglyphs = 0;
- x = y = 0;
- for (i = 0; i < array->stack.len; i++) {
- const csi_object_t *obj = &array->stack.objects[i];
- int type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_ARRAY: {
- const csi_array_t *glyph_array = obj->datum.array;
- for (j = 0; j < glyph_array->stack.len; j++) {
- unsigned long g;
- int gi;
- obj = &glyph_array->stack.objects[j];
- if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
- break;
- g = obj->datum.integer;
- glyphs[nglyphs].index = g;
- glyphs[nglyphs].x = x;
- glyphs[nglyphs].y = y;
- gi = g % ARRAY_LENGTH (cache->have_glyph_advance);
- if (cache->have_glyph_advance[gi] != g) {
- cairo_text_extents_t extents;
- cairo_scaled_font_glyph_extents (scaled_font,
- &glyphs[nglyphs], 1,
- &extents);
- cache->glyph_advance[gi][0] = extents.x_advance;
- cache->glyph_advance[gi][1] = extents.y_advance;
- cache->have_glyph_advance[gi] = g;
- }
- x += cache->glyph_advance[gi][0];
- y += cache->glyph_advance[gi][1];
- nglyphs++;
- }
- break;
- }
- case CSI_OBJECT_TYPE_STRING: {
- const csi_string_t *glyph_string = obj->datum.string;
- for (j = 0; j < glyph_string->len; j++) {
- uint8_t g;
- g = glyph_string->string[j];
- glyphs[nglyphs].index = g;
- glyphs[nglyphs].x = x;
- glyphs[nglyphs].y = y;
- if (cache->have_glyph_advance[g] != g) {
- cairo_text_extents_t extents;
- cairo_scaled_font_glyph_extents (scaled_font,
- &glyphs[nglyphs], 1,
- &extents);
- cache->glyph_advance[g][0] = extents.x_advance;
- cache->glyph_advance[g][1] = extents.y_advance;
- cache->have_glyph_advance[g] = g;
- }
- x += cache->glyph_advance[g][0];
- y += cache->glyph_advance[g][1];
- nglyphs++;
- }
- break;
- }
- case CSI_OBJECT_TYPE_INTEGER:
- case CSI_OBJECT_TYPE_REAL: /* dx or x*/
- dx = csi_number_get_value (obj);
- if (i+1 == array->stack.len)
- break;
- type = csi_object_get_type (&array->stack.objects[i+1]);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- case CSI_OBJECT_TYPE_REAL: /* y */
- y = csi_number_get_value (&array->stack.objects[i+1]);
- x = dx;
- i++;
- break;
- default:
- x += dx;
- }
- }
- }
- return nglyphs;
- }
- static csi_status_t
- _glyph_path (csi_t *ctx)
- {
- csi_array_t *array;
- csi_status_t status;
- cairo_t *cr;
- cairo_glyph_t stack_glyphs[256], *glyphs;
- csi_integer_t nglyphs, i;
- check (2);
- status = _csi_ostack_get_array (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- /* count glyphs */
- nglyphs = 0;
- for (i = 0; i < array->stack.len; i++) {
- csi_object_t *obj = &array->stack.objects[i];
- int type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_ARRAY:
- nglyphs += obj->datum.array->stack.len;
- break;
- case CSI_OBJECT_TYPE_STRING:
- nglyphs += obj->datum.string->len;
- break;
- }
- }
- if (nglyphs == 0) {
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
- if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
- if (_csi_unlikely (glyphs == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else
- glyphs = stack_glyphs;
- nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- cairo_glyph_path (cr, glyphs, nglyphs);
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _gray (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double g;
- check (1);
- status = _csi_ostack_get_number (ctx, 0, &g);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1);
- return push (&obj);
- }
- static csi_status_t
- _gt (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *a, *b;
- int cmp;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- status = csi_object_compare (a, b, &cmp);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return _csi_push_ostack_boolean (ctx, cmp > 0);
- }
- static csi_status_t
- _identity (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- status = csi_matrix_new (ctx, &obj);
- if (_csi_unlikely (status))
- return status;
- return push (&obj);
- }
- static csi_status_t
- _if (csi_t *ctx)
- {
- csi_array_t *proc;
- csi_boolean_t predicate = FALSE; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_procedure (ctx, 0, &proc);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_boolean (ctx, 1, &predicate);
- if (_csi_unlikely (status))
- return status;
- proc->base.ref++;
- pop (2);
- if (predicate)
- status = _csi_array_execute (ctx, proc);
- if (--proc->base.ref == 0)
- csi_array_free (ctx, proc);
- return status;
- }
- static csi_status_t
- _ifelse (csi_t *ctx)
- {
- csi_array_t *true_proc, *false_proc;
- csi_boolean_t predicate = FALSE; /* silence the compiler */
- csi_status_t status;
- check (3);
- status = _csi_ostack_get_procedure (ctx, 0, &false_proc);
- if (_csi_unlikely (status))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = _csi_ostack_get_procedure (ctx, 1, &true_proc);
- if (_csi_unlikely (status))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = _csi_ostack_get_boolean (ctx, 2, &predicate);
- if (_csi_unlikely (status))
- return status;
- true_proc->base.ref++;
- false_proc->base.ref++;
- pop (3);
- if (predicate)
- status = _csi_array_execute (ctx, true_proc);
- else
- status = _csi_array_execute (ctx, false_proc);
- if (--true_proc->base.ref == 0)
- csi_array_free (ctx, true_proc);
- if (--false_proc->base.ref == 0)
- csi_array_free (ctx, false_proc);
- return status;
- }
- static csi_status_t
- _image_read_raw (csi_t *ctx,
- csi_object_t *src,
- cairo_format_t format,
- int width, int height,
- cairo_surface_t **image_out)
- {
- cairo_surface_t *image;
- uint8_t *bp, *data;
- int rem, len, ret, x, rowlen, instride, stride;
- cairo_status_t status;
- if (width == 0 || height == 0) {
- *image_out = cairo_image_surface_create (format, 0, 0);
- return CSI_STATUS_SUCCESS;
- }
- if (ctx->hooks.create_source_image != NULL) {
- image = ctx->hooks.create_source_image (ctx->hooks.closure,
- format, width, height,
- 0);
- stride = cairo_image_surface_get_stride (image);
- data = cairo_image_surface_get_data (image);
- } else {
- stride = cairo_format_stride_for_width (format, width);
- data = malloc (stride * height);
- if (data == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- image = cairo_image_surface_create_for_data (data, format,
- width, height, stride);
- status = cairo_surface_set_user_data (image,
- (const cairo_user_data_key_t *) image,
- data, free);
- if (status) {
- cairo_surface_destroy (image);
- free (image);
- return status;
- }
- }
- switch (format) {
- case CAIRO_FORMAT_A1:
- instride = rowlen = (width+7)/8;
- break;
- case CAIRO_FORMAT_A8:
- instride = rowlen = width;
- break;
- case CAIRO_FORMAT_RGB16_565:
- instride = rowlen = 2 * width;
- break;
- case CAIRO_FORMAT_RGB24:
- rowlen = 3 * width;
- instride = 4 *width;
- break;
- default:
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_ARGB32:
- instride = rowlen = 4 * width;
- break;
- }
- len = rowlen * height;
- if (rowlen == instride &&
- src->type == CSI_OBJECT_TYPE_STRING &&
- len == src->datum.string->deflate)
- {
- csi_string_t *s = src->datum.string;
- unsigned long out = s->deflate;
- switch (s->method) {
- default:
- case NONE:
- err_decompress:
- cairo_surface_destroy (image);
- return _csi_error (CSI_STATUS_READ_ERROR);
- case ZLIB:
- #if HAVE_ZLIB
- if (uncompress ((Bytef *) data, &out,
- (Bytef *) s->string, s->len) != Z_OK)
- #endif
- goto err_decompress;
- break;
- case LZO:
- #if HAVE_LZO
- if (lzo2a_decompress ((Bytef *) s->string, s->len,
- (Bytef *) data, &out,
- NULL))
- #endif
- goto err_decompress;
- break;
- }
- }
- else
- {
- csi_object_t file;
- status = csi_object_as_file (ctx, src, &file);
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (image);
- return status;
- }
- bp = data;
- rem = len;
- while (rem) {
- ret = csi_file_read (file.datum.file, bp, rem);
- if (_csi_unlikely (ret == 0)) {
- cairo_surface_destroy (image);
- return _csi_error (CSI_STATUS_READ_ERROR);
- }
- rem -= ret;
- bp += ret;
- }
- if (len != height * stride) {
- while (--height) {
- uint8_t *row = data + height * stride;
- /* XXX pixel conversion */
- switch (format) {
- case CAIRO_FORMAT_A1:
- for (x = rowlen; x--; ) {
- uint8_t byte = *--bp;
- row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
- }
- break;
- case CAIRO_FORMAT_A8:
- for (x = width; x--; )
- row[x] = *--bp;
- break;
- case CAIRO_FORMAT_RGB16_565:
- for (x = width; x--; ) {
- #ifdef WORDS_BIGENDIAN
- row[2*x + 1] = *--bp;
- row[2*x + 0] = *--bp;
- #else
- row[2*x + 0] = *--bp;
- row[2*x + 1] = *--bp;
- #endif
- }
- break;
- case CAIRO_FORMAT_RGB24:
- for (x = width; x--; ) {
- #ifdef WORDS_BIGENDIAN
- row[4*x + 3] = *--bp;
- row[4*x + 2] = *--bp;
- row[4*x + 1] = *--bp;
- row[4*x + 0] = 0xff;
- #else
- row[4*x + 0] = *--bp;
- row[4*x + 1] = *--bp;
- row[4*x + 2] = *--bp;
- row[4*x + 3] = 0xff;
- #endif
- }
- break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_ARGB32:
- /* stride == width */
- break;
- }
- memset (row + instride, 0, stride - instride);
- }
- /* need to treat last row carefully */
- switch (format) {
- case CAIRO_FORMAT_A1:
- for (x = rowlen; x--; ) {
- uint8_t byte = *--bp;
- data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
- }
- break;
- case CAIRO_FORMAT_A8:
- for (x = width; x--; )
- data[x] = *--bp;
- break;
- case CAIRO_FORMAT_RGB16_565:
- for (x = width; x--; ) {
- #ifdef WORDS_BIGENDIAN
- data[2*x + 1] = *--bp;
- data[2*x + 0] = *--bp;
- #else
- data[2*x + 0] = *--bp;
- data[2*x + 1] = *--bp;
- #endif
- }
- break;
- case CAIRO_FORMAT_RGB24:
- for (x = width; --x>1; ) {
- #ifdef WORDS_BIGENDIAN
- data[4*x + 3] = *--bp;
- data[4*x + 2] = *--bp;
- data[4*x + 1] = *--bp;
- data[4*x + 0] = 0xff;
- #else
- data[4*x + 0] = *--bp;
- data[4*x + 1] = *--bp;
- data[4*x + 2] = *--bp;
- data[4*x + 3] = 0xff;
- #endif
- }
- if (width > 1) {
- uint8_t rgb[2][3];
- /* shuffle the last couple of overlapping pixels */
- rgb[1][0] = data[5];
- rgb[1][1] = data[4];
- rgb[1][2] = data[3];
- rgb[0][0] = data[2];
- rgb[0][1] = data[1];
- rgb[0][2] = data[0];
- #ifdef WORDS_BIGENDIAN
- data[4] = 0xff;
- data[5] = rgb[1][2];
- data[6] = rgb[1][1];
- data[7] = rgb[1][0];
- data[0] = 0xff;
- data[1] = rgb[0][2];
- data[2] = rgb[0][1];
- data[3] = rgb[0][0];
- #else
- data[7] = 0xff;
- data[6] = rgb[1][2];
- data[5] = rgb[1][1];
- data[4] = rgb[1][0];
- data[3] = 0xff;
- data[2] = rgb[0][2];
- data[1] = rgb[0][1];
- data[0] = rgb[0][0];
- #endif
- } else {
- #ifdef WORDS_BIGENDIAN
- data[0] = 0xff;
- data[1] = data[0];
- data[2] = data[1];
- data[3] = data[2];
- #else
- data[3] = data[0];
- data[0] = data[2];
- data[2] = data[3];
- data[3] = 0xff;
- #endif
- }
- break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_ARGB32:
- /* stride == width */
- break;
- }
- memset (data + instride, 0, stride - instride);
- } else {
- #ifndef WORDS_BIGENDIAN
- switch (format) {
- case CAIRO_FORMAT_A1:
- for (x = 0; x < len; x++) {
- uint8_t byte = data[x];
- data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
- }
- break;
- case CAIRO_FORMAT_RGB16_565:
- {
- uint32_t *rgba = (uint32_t *) data;
- for (x = len/2; x--; rgba++) {
- *rgba = bswap_16 (*rgba);
- }
- }
- break;
- case CAIRO_FORMAT_ARGB32:
- {
- uint32_t *rgba = (uint32_t *) data;
- for (x = len/4; x--; rgba++) {
- *rgba = bswap_32 (*rgba);
- }
- }
- break;
- case CAIRO_FORMAT_A8:
- break;
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_RGB24:
- case CAIRO_FORMAT_INVALID:
- default:
- break;
- }
- #endif
- }
- csi_object_free (ctx, &file);
- }
- cairo_surface_mark_dirty (image);
- *image_out = image;
- return CSI_STATUS_SUCCESS;
- }
- static cairo_status_t
- png_read_func (void *closure, uint8_t *data, unsigned int len)
- {
- int ret;
- ret = csi_file_read (closure, data, len);
- if ((unsigned int) ret != len)
- return CAIRO_STATUS_READ_ERROR;
- return CAIRO_STATUS_SUCCESS;
- }
- static csi_status_t
- _image_read_png (csi_file_t *src, cairo_surface_t **out)
- {
- #if CAIRO_HAS_PNG_FUNCTIONS
- *out = cairo_image_surface_create_from_png_stream (png_read_func, src);
- return cairo_surface_status (*out);
- #else
- return CAIRO_STATUS_READ_ERROR;
- #endif
- }
- struct _image_tag {
- csi_t *ctx;
- csi_blob_t blob;
- cairo_surface_t *surface;
- };
- static void
- _image_tag_done (void *closure)
- {
- struct _image_tag *tag = closure;
- csi_t *ctx = tag->ctx;
- ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list);
- _csi_slab_free (ctx, tag, sizeof (*tag));
- cairo_script_interpreter_destroy (ctx);
- }
- static void
- _image_hash (csi_blob_t *blob,
- cairo_surface_t *surface)
- {
- uint32_t value;
- value = cairo_image_surface_get_width (surface);
- _csi_blob_hash (blob, &value, 1);
- value = cairo_image_surface_get_height (surface);
- _csi_blob_hash (blob, &value, 1);
- value = cairo_image_surface_get_format (surface);
- _csi_blob_hash (blob, &value, 1);
- }
- static cairo_surface_t *
- _image_cached (csi_t *ctx, cairo_surface_t *surface)
- {
- csi_blob_t tmpl;
- csi_list_t *link;
- uint8_t *data;
- int stride, height;
- struct _image_tag *tag;
- /* check for an existing image */
- data = cairo_image_surface_get_data (surface);
- stride = cairo_image_surface_get_stride (surface);
- height = cairo_image_surface_get_height (surface);
- _csi_blob_init (&tmpl, data, stride * height);
- _image_hash (&tmpl, surface);
- link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
- if (link) {
- cairo_surface_destroy (surface);
- tag = csi_container_of (link, struct _image_tag, blob.list);
- return cairo_surface_reference (tag->surface);
- }
- /* none found, insert a tag for this one */
- tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag));
- if (tag == NULL)
- return surface;
- ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list);
- tag->ctx = cairo_script_interpreter_reference (ctx);
- tag->blob.hash = tmpl.hash;
- tag->blob.bytes = tmpl.bytes;
- tag->blob.len = tmpl.len;
- tag->surface = surface;
- if (cairo_surface_set_user_data (surface, &_csi_blob_key,
- tag, _image_tag_done))
- {
- _image_tag_done (tag);
- }
- return surface;
- }
- static csi_status_t
- _image_load_from_dictionary (csi_t *ctx,
- csi_dictionary_t *dict,
- cairo_surface_t **image_out)
- {
- csi_object_t obj, key;
- long width;
- long height;
- long format;
- cairo_surface_t *image = NULL; /* silence the compiler */
- csi_status_t status;
- /* check for "status? */
- status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height);
- if (_csi_unlikely (status))
- return status;
- format = CAIRO_FORMAT_ARGB32;
- status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format);
- if (_csi_unlikely (status))
- return status;
- status = csi_name_new_static (ctx, &key, "source");
- if (_csi_unlikely (status))
- return status;
- if (csi_dictionary_has (dict, key.datum.name)) {
- enum mime_type mime_type;
- csi_object_t file;
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- status = csi_name_new_static (ctx, &key, "mime-type");
- if (_csi_unlikely (status))
- return status;
- mime_type = MIME_TYPE_NONE;
- if (csi_dictionary_has (dict, key.datum.name)) {
- csi_object_t type_obj;
- const char *type_str;
- int type;
- status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj);
- if (_csi_unlikely (status))
- return status;
- type = csi_object_get_type (&type_obj);
- switch (type) {
- case CSI_OBJECT_TYPE_STRING:
- type_str = type_obj.datum.string->string;
- break;
- case CSI_OBJECT_TYPE_NAME:
- type_str = (char *) type_obj.datum.name;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0)
- mime_type = MIME_TYPE_PNG;
- }
- /* XXX hook for general mime-type decoder */
- switch (mime_type) {
- case MIME_TYPE_NONE:
- status = _image_read_raw (ctx, &obj, format, width, height, &image);
- break;
- case MIME_TYPE_PNG:
- status = csi_object_as_file (ctx, &obj, &file);
- if (_csi_unlikely (status))
- return status;
- status = _image_read_png (file.datum.file, &image);
- csi_object_free (ctx, &file);
- break;
- }
- if (_csi_unlikely (status))
- return status;
- image = _image_cached (ctx, image);
- } else
- image = cairo_image_surface_create (format, width, height);
- *image_out = image;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _image (csi_t *ctx)
- {
- csi_dictionary_t *dict;
- cairo_surface_t *image;
- csi_status_t status;
- csi_object_t obj;
- check (1);
- status = _csi_ostack_get_dictionary (ctx, 0, &dict);
- if (_csi_unlikely (status))
- return status;
- status = _image_load_from_dictionary (ctx, dict, &image);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = image;
- return push (&obj);
- }
- static csi_status_t
- _index (csi_t *ctx)
- {
- csi_status_t status;
- long n;
- check (1);
- status = _csi_ostack_get_integer (ctx, 0, &n);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- check (n);
- return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n));
- }
- static csi_status_t
- _integer (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- break;
- case CSI_OBJECT_TYPE_REAL:
- obj->datum.integer = obj->datum.real;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- obj->type = CSI_OBJECT_TYPE_INTEGER;
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _invert (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- cairo_matrix_t m;
- check (1);
- status = _csi_ostack_get_matrix (ctx, 0, &m);
- if (_csi_unlikely (status))
- return status;
- cairo_matrix_invert (&m);
- status = csi_matrix_new_from_matrix (ctx, &obj, &m);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- return push (&obj);
- }
- static csi_status_t
- _le (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *a, *b;
- int cmp;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- status = csi_object_compare (a, b, &cmp);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return _csi_push_ostack_boolean (ctx, cmp <= 0);
- }
- static csi_status_t
- _linear (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double x1, y1, x2, y2;
- check (4);
- status = _csi_ostack_get_number (ctx, 0, &y2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &y1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &x1);
- if (_csi_unlikely (status))
- return status;
- pop (4);
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
- return push (&obj);
- }
- static csi_status_t
- _line_to (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- int type;
- double x, y;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- /* XXX path object */
- obj = _csi_peek_ostack (ctx, 2);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_line_to (obj->datum.cr, x, y);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_mesh_pattern_line_to (obj->datum.pattern, x, y);
- break;
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _lt (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *a, *b;
- int cmp;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- status = csi_object_compare (a, b, &cmp);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return _csi_push_ostack_boolean (ctx, cmp < 0);
- }
- static csi_status_t
- _mark (csi_t *ctx)
- {
- return _csi_push_ostack_mark (ctx);
- }
- static csi_status_t
- _ne (csi_t *ctx)
- {
- csi_object_t *a, *b;
- csi_boolean_t v;
- check (2);
- b = _csi_peek_ostack (ctx, 0);
- a = _csi_peek_ostack (ctx, 1);
- v = ! csi_object_eq (a, b);
- pop (2);
- return _csi_push_ostack_boolean (ctx, v);
- }
- static csi_status_t
- _neg (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- obj->datum.integer = -obj->datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- obj->datum.real = -obj->datum.real;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _not (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_BOOLEAN:
- obj->datum.boolean = ! obj->datum.boolean;
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- obj->type = CSI_OBJECT_TYPE_BOOLEAN;
- obj->datum.boolean = ! obj->datum.integer;
- break;
- case CSI_OBJECT_TYPE_REAL:
- obj->type = CSI_OBJECT_TYPE_BOOLEAN;
- obj->datum.boolean = obj->datum.real == 0.0;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _new_path (csi_t *ctx)
- {
- /* XXX handle path object */
- return _do_cairo_op (ctx, cairo_new_path);
- }
- static csi_status_t
- _new_sub_path (csi_t *ctx)
- {
- /* XXX handle path object */
- return _do_cairo_op (ctx, cairo_new_sub_path);
- }
- static csi_status_t
- _null (csi_t *ctx)
- {
- return _csi_push_ostack_null (ctx);
- }
- static csi_status_t
- _mask (csi_t *ctx)
- {
- cairo_t *cr;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_pattern (ctx, 0, &pattern);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_mask (cr, pattern);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _matrix (csi_t *ctx)
- {
- csi_object_t *obj, matrix;
- double v[6];
- csi_status_t status;
- int n;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- if (csi_object_is_number (obj)) {
- check (6);
- for (n = 6; n--; ) {
- status = _csi_ostack_get_number (ctx, 5-n, &v[n]);
- if (_csi_unlikely (status))
- return status;
- }
- status = csi_matrix_new_from_values (ctx, &matrix, v);
- if (_csi_unlikely (status))
- return status;
- pop (6);
- } else {
- csi_array_t *array;
- status = _csi_ostack_get_array (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = csi_matrix_new_from_array (ctx, &matrix, array);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- }
- return push (&matrix);
- }
- static csi_status_t
- _map_to_image (csi_t *ctx)
- {
- csi_object_t obj;
- csi_array_t *array;
- csi_status_t status;
- cairo_rectangle_int_t extents, *r;
- cairo_surface_t *surface;
- check (2);
- status = _csi_ostack_get_array (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 1, &surface);
- if (_csi_unlikely (status))
- return status;
- switch (array->stack.len) {
- case 0:
- r = NULL;
- break;
- case 4:
- extents.x = floor (_csi_object_as_real (&array->stack.objects[0]));
- extents.y = floor (_csi_object_as_real (&array->stack.objects[1]));
- extents.width = ceil (_csi_object_as_real (&array->stack.objects[2]));
- extents.height = ceil (_csi_object_as_real (&array->stack.objects[3]));
- r = &extents;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r));
- pop (1);
- return push (&obj);
- }
- static csi_status_t
- _unmap_image (csi_t *ctx)
- {
- cairo_surface_t *surface, *image;
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_surface (ctx, 0, &image);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 1, &surface);
- if (_csi_unlikely (status))
- return status;
- cairo_surface_unmap_image (surface, image);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mesh (csi_t *ctx)
- {
- csi_object_t obj;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_mesh ();
- return push (&obj);
- }
- static csi_status_t
- _mesh_begin_patch (csi_t *ctx)
- {
- csi_status_t status;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- check (1);
- status = _csi_ostack_get_pattern (ctx, 0, &pattern);
- if (_csi_unlikely (status))
- return status;
- cairo_mesh_pattern_begin_patch (pattern);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mesh_end_patch (csi_t *ctx)
- {
- csi_status_t status;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- check (1);
- status = _csi_ostack_get_pattern (ctx, 0, &pattern);
- if (_csi_unlikely (status))
- return status;
- cairo_mesh_pattern_end_patch (pattern);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mesh_set_control_point (csi_t *ctx)
- {
- csi_status_t status;
- double x, y;
- csi_integer_t point;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- check (4);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 2, &point);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_pattern (ctx, 3, &pattern);
- if (_csi_unlikely (status))
- return status;
- cairo_mesh_pattern_set_control_point (pattern, point, x, y);
- pop (3);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mesh_set_corner_color (csi_t *ctx)
- {
- csi_status_t status;
- double r, g, b, a;
- csi_integer_t corner;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- check (6);
- status = _csi_ostack_get_number (ctx, 0, &a);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 4, &corner);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_pattern (ctx, 5, &pattern);
- if (_csi_unlikely (status))
- return status;
- cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a);
- pop (5);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mod (csi_t *ctx)
- {
- csi_integer_t x, y;
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- return _csi_push_ostack_integer (ctx, x % y);
- }
- static csi_status_t
- _move_to (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- int type;
- double x, y;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 2);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_move_to (obj->datum.cr, x, y);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_mesh_pattern_move_to (obj->datum.pattern, x, y);
- break;
- /* XXX path object */
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _mul (csi_t *ctx)
- {
- csi_object_t *A;
- csi_object_t *B;
- csi_object_type_t type_a, type_b;
- check (2);
- B = _csi_peek_ostack (ctx, 0);
- A = _csi_peek_ostack (ctx, 1);
- type_a = csi_object_get_type (A);
- if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
- type_a == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- type_b = csi_object_get_type (B);
- if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
- type_b == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- if (type_a == CSI_OBJECT_TYPE_REAL &&
- type_b == CSI_OBJECT_TYPE_REAL)
- {
- return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real);
- }
- else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
- type_b == CSI_OBJECT_TYPE_INTEGER)
- {
- return _csi_push_ostack_integer (ctx,
- A->datum.integer * B->datum.integer);
- }
- else
- {
- double v;
- if (type_a == CSI_OBJECT_TYPE_REAL)
- v = A->datum.real;
- else
- v = A->datum.integer;
- if (type_b == CSI_OBJECT_TYPE_REAL)
- v *= B->datum.real;
- else
- v *= B->datum.integer;
- return _csi_push_ostack_real (ctx, v);
- }
- }
- static csi_status_t
- _or (csi_t *ctx)
- {
- csi_object_t *a, *b;
- int type;
- check (2);
- a = _csi_peek_ostack (ctx, 0);
- b = _csi_peek_ostack (ctx, 1);
- if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- pop (2);
- type = csi_object_get_type (a);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- return _csi_push_ostack_integer (ctx,
- a->datum.integer | b->datum.integer);
- case CSI_OBJECT_TYPE_BOOLEAN:
- return _csi_push_ostack_boolean (ctx,
- a->datum.boolean | b->datum.boolean);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _paint (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_paint);
- }
- static csi_status_t
- _paint_with_alpha (csi_t *ctx)
- {
- cairo_t *cr;
- csi_status_t status;
- double alpha;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &alpha);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_paint_with_alpha (cr, alpha);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _pattern (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- cairo_surface_t *surface;
- check (1);
- status = _csi_ostack_get_surface (ctx, 0, &surface);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_for_surface (surface);
- pop (1);
- return push (&obj);
- }
- static csi_status_t
- _pop (csi_t *ctx)
- {
- check (1);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _pop_group (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- cairo_t *cr;
- check (1);
- status = _csi_ostack_get_context (ctx, 0, &cr);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pop_group (cr);
- return push (&obj);
- }
- static csi_status_t
- _push_group (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- long content;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &content);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_push_group_with_content (cr, content);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _radial (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double x1, y1, r1, x2, y2, r2;
- check (6);
- status = _csi_ostack_get_number (ctx, 0, &r2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &y2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &x2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &r1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &y1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 5, &x1);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2);
- pop (6);
- return push (&obj);
- }
- static csi_status_t
- _rectangle (csi_t *ctx)
- {
- csi_status_t status;
- double x, y;
- double w, h;
- cairo_t *cr;
- check (5);
- status = _csi_ostack_get_number (ctx, 0, &h);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &w);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 4, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX path object */
- cairo_rectangle (cr, x, y, w, h);
- pop(4);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _rel_curve_to (csi_t *ctx)
- {
- csi_status_t status;
- double x1, y1;
- double x2, y2;
- double x3, y3;
- cairo_t *cr;
- check (7);
- status = _csi_ostack_get_number (ctx, 0, &y3);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x3);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &y2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &x2);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 4, &y1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 5, &x1);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 6, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX path object */
- cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3);
- pop (6);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _rel_line_to (csi_t *ctx)
- {
- csi_status_t status;
- double x, y;
- cairo_t *cr;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 2, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX path object */
- cairo_rel_line_to (cr, x, y);
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _rel_move_to (csi_t *ctx)
- {
- csi_status_t status;
- double x, y;
- cairo_t *cr;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 2, &cr);
- if (_csi_unlikely (status))
- return status;
- /* XXX path object */
- cairo_rel_move_to (cr, x, y);
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _repeat (csi_t *ctx)
- {
- csi_array_t *proc;
- csi_integer_t count;
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_procedure (ctx, 0, &proc);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &count);
- if (_csi_unlikely (status))
- return status;
- if (_csi_unlikely (count < 0))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- proc->base.ref++;
- pop (2);
- while (count--) {
- status = _csi_array_execute (ctx, proc);
- if (_csi_unlikely (status))
- break;
- }
- if (--proc->base.ref == 0)
- csi_array_free (ctx, proc);
- return status;
- }
- static csi_status_t
- _reset_clip (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_reset_clip);
- }
- static csi_status_t
- _restore (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_restore);
- }
- static csi_status_t
- _rgb (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double r,g,b;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &r);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_rgb (r, g, b);
- pop (3);
- return push (&obj);
- }
- static csi_status_t
- _rgba (csi_t *ctx)
- {
- csi_object_t obj;
- csi_status_t status;
- double r,g,b,a;
- check (4);
- status = _csi_ostack_get_number (ctx, 0, &a);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &r);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_PATTERN;
- obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a);
- pop (4);
- return push (&obj);
- }
- static csi_status_t
- _roll (csi_t *ctx)
- {
- csi_status_t status;
- long j, n;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &j);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &n);
- if (_csi_unlikely (status))
- return status;
- pop (2);
- check (n);
- return _csi_stack_roll (ctx, &ctx->ostack, j, n);
- }
- static csi_status_t
- _rotate (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_status_t status;
- double theta;
- int type;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &theta);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_rotate (obj->datum.cr, theta);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- {
- cairo_matrix_t ctm;
- cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
- cairo_matrix_rotate (&ctm, theta);
- cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
- }
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- cairo_matrix_rotate (&obj->datum.matrix->matrix, theta);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _save (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_save);
- }
- static csi_status_t
- _scale (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_status_t status;
- double x, y;
- int type;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 2);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_scale (obj->datum.cr, x, y);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- {
- cairo_matrix_t ctm;
- cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
- cairo_matrix_scale (&ctm, x, y);
- cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
- }
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- cairo_matrix_scale (&obj->datum.matrix->matrix, x, y);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _font_options_load_from_dictionary (csi_t *ctx,
- csi_dictionary_t *dict,
- cairo_font_options_t *options)
- {
- const struct {
- const char *key;
- void (*setter) (cairo_font_options_t *, int val);
- } properties[] = {
- { "antialias",
- (void (*)(cairo_font_options_t *, int val))
- cairo_font_options_set_antialias },
- { "subpixel-order",
- (void (*)(cairo_font_options_t *, int val))
- cairo_font_options_set_subpixel_order },
- { "hint-style",
- (void (*)(cairo_font_options_t *, int val))
- cairo_font_options_set_hint_style },
- { "hint-metrics",
- (void (*)(cairo_font_options_t *, int val))
- cairo_font_options_set_hint_metrics },
- { NULL, NULL },
- }, *prop = properties;
- while (prop->key != NULL) {
- csi_object_t key, value;
- csi_status_t status;
- status = csi_name_new_static (ctx, &key, prop->key);
- if (_csi_unlikely (status))
- return status;
- if (csi_dictionary_has (dict, key.datum.name)) {
- status = csi_dictionary_get (ctx, dict, key.datum.name, &value);
- if (_csi_unlikely (status))
- return status;
- if (_csi_unlikely (csi_object_get_type (&value) !=
- CSI_OBJECT_TYPE_INTEGER))
- {
- csi_object_free (ctx, &value);
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- prop->setter (options, value.datum.integer);
- }
- prop++;
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _scaled_font (csi_t *ctx)
- {
- csi_object_t obj;
- csi_dictionary_t *dict;
- cairo_font_face_t *font_face = NULL; /* silence the compiler */
- cairo_matrix_t font_matrix, ctm;
- cairo_font_options_t *options;
- csi_status_t status;
- check (4);
- status = _csi_ostack_get_dictionary (ctx, 0, &dict);
- if (_csi_unlikely (status))
- return status;
- options = cairo_font_options_create ();
- status = _font_options_load_from_dictionary (ctx, dict, options);
- if (_csi_unlikely (status)) {
- cairo_font_options_destroy (options);
- return status;
- }
- status = _csi_ostack_get_matrix (ctx, 1, &ctm);
- if (_csi_unlikely (status)) {
- cairo_font_options_destroy (options);
- return status;
- }
- status = _csi_ostack_get_matrix (ctx, 2, &font_matrix);
- if (_csi_unlikely (status)) {
- cairo_font_options_destroy (options);
- return status;
- }
- status = _csi_ostack_get_font_face (ctx, 3, &font_face);
- if (_csi_unlikely (status)) {
- cairo_font_options_destroy (options);
- return status;
- }
- obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
- obj.datum.scaled_font = cairo_scaled_font_create (font_face,
- &font_matrix,
- &ctm,
- options);
- cairo_font_options_destroy (options);
- pop (4);
- return push (&obj);
- }
- static csi_status_t
- _select_font_face (csi_t *ctx)
- {
- cairo_t *cr;
- long weight;
- long slant;
- csi_string_t *family;
- csi_status_t status;
- check (4);
- status = _csi_ostack_get_integer (ctx, 0, &weight);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &slant);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_string (ctx, 2, &family);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 3, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_select_font_face (cr, family->string, slant, weight);
- pop (3);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _context_set (csi_t *ctx,
- cairo_t *cr,
- csi_name_t key,
- csi_object_t *obj)
- {
- if (strcmp ((char *) key, "source") == 0) {
- if (_csi_unlikely (csi_object_get_type (obj) !=
- CSI_OBJECT_TYPE_PATTERN))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- cairo_set_source (cr, obj->datum.pattern);
- return CSI_STATUS_SUCCESS;
- }
- if (strcmp ((char *) key, "scaled-font") == 0) {
- if (_csi_unlikely (csi_object_get_type (obj) !=
- CSI_OBJECT_TYPE_SCALED_FONT))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- cairo_set_scaled_font (cr, obj->datum.scaled_font);
- return CSI_STATUS_SUCCESS;
- }
- if (strcmp ((char *) key, "font-face") == 0) {
- if (_csi_unlikely (csi_object_get_type (obj) !=
- CSI_OBJECT_TYPE_FONT))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- cairo_set_font_face (cr, obj->datum.font_face);
- return CSI_STATUS_SUCCESS;
- }
- /* return _proxy_set()? */
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- static csi_status_t
- _set (csi_t *ctx)
- {
- csi_object_t *key, *value, *dst;
- csi_status_t status;
- int type;
- check (3);
- value = _csi_peek_ostack (ctx, 0);
- key = _csi_peek_ostack (ctx, 1);
- dst = _csi_peek_ostack (ctx, 2);
- type = csi_object_get_type (dst);
- switch (type) {
- case CSI_OBJECT_TYPE_DICTIONARY:
- if (_csi_unlikely (csi_object_get_type (key) !=
- CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = csi_dictionary_put (ctx,
- dst->datum.dictionary,
- key->datum.name,
- value);
- break;
- case CSI_OBJECT_TYPE_ARRAY:
- if (_csi_unlikely (csi_object_get_type (key) !=
- CSI_OBJECT_TYPE_INTEGER))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = csi_array_put (ctx,
- dst->datum.array,
- key->datum.integer,
- value);
- break;
- case CSI_OBJECT_TYPE_CONTEXT:
- if (_csi_unlikely (csi_object_get_type (key) !=
- CSI_OBJECT_TYPE_NAME))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- status = _context_set (ctx,
- dst->datum.cr,
- key->datum.name,
- value);
- break;
- case CSI_OBJECT_TYPE_STRING:
- #if 0
- status = csi_string_put (dst, key, value);
- break;
- #endif
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- return status;
- }
- static csi_status_t
- _set_antialias (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- long antialias;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &antialias);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_antialias (cr, antialias);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_dash (csi_t *ctx)
- {
- csi_array_t *array;
- csi_status_t status;
- cairo_t *cr;
- double offset;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &offset);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_array (ctx, 1, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 2, &cr);
- if (_csi_unlikely (status))
- return status;
- if (array->stack.len == 0) {
- cairo_set_dash (cr, NULL, 0., 0.);
- } else {
- double stack_dashes[8];
- double *dashes;
- csi_integer_t n;
- if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) {
- dashes = stack_dashes;
- } else {
- if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len);
- if (_csi_unlikely (dashes == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- for (n = 0; n < array->stack.len; n++) {
- if (_csi_unlikely (! csi_object_is_number
- (&array->stack.objects[n])))
- {
- if (dashes != stack_dashes)
- _csi_free (ctx, dashes);
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- dashes[n] = csi_number_get_value (&array->stack.objects[n]);
- }
- cairo_set_dash (cr, dashes, n, offset);
- if (dashes != stack_dashes)
- _csi_free (ctx, dashes);
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_device_offset (csi_t *ctx)
- {
- csi_status_t status;
- cairo_surface_t *surface;
- double x, y;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 2, &surface);
- if (_csi_unlikely (status))
- return status;
- cairo_surface_set_device_offset (surface, x, y);
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_device_scale (csi_t *ctx)
- {
- csi_status_t status;
- cairo_surface_t *surface;
- double x, y;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 2, &surface);
- if (_csi_unlikely (status))
- return status;
- cairo_surface_set_device_scale (surface, x, y);
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_extend (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- long extend;
- int type;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &extend);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_pattern_set_extend (cairo_get_source (obj->datum.cr),
- extend);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_pattern_set_extend (obj->datum.pattern, extend);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_fallback_resolution (csi_t *ctx)
- {
- csi_status_t status;
- cairo_surface_t *surface;
- double dpi_x, dpi_y;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &dpi_y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &dpi_x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 2, &surface);
- if (_csi_unlikely (status))
- return status;
- cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y);
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_fill_rule (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- long fill_rule;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &fill_rule);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_fill_rule (cr, fill_rule);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_filter (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- long filter;
- int type;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &filter);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_pattern_set_filter (cairo_get_source (obj->datum.cr),
- filter);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_pattern_set_filter (obj->datum.pattern, filter);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_font_face (csi_t *ctx)
- {
- cairo_t *cr;
- cairo_font_face_t *font = NULL; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_font_face (ctx, 0, &font);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_font_face (cr, font);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_font_options (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- csi_dictionary_t *dict;
- cairo_font_options_t *options;
- check (2);
- status = _csi_ostack_get_dictionary (ctx, 0, &dict);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- options = cairo_font_options_create ();
- status = _font_options_load_from_dictionary (ctx, dict, options);
- if (_csi_unlikely (status))
- return status;
- cairo_set_font_options (cr, options);
- cairo_font_options_destroy (options);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_font_matrix (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- cairo_matrix_t m;
- check (2);
- status = _csi_ostack_get_matrix (ctx, 0, &m);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_font_matrix (cr, &m);
- pop(1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_font_size (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- double size;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &size);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_font_size (cr, size);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_line_cap (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- long line_cap;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &line_cap);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_line_cap (cr, line_cap);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_line_join (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- long line_join;
- status = _csi_ostack_get_integer (ctx, 0, &line_join);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_line_join (cr, line_join);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_line_width (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- double line_width;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &line_width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_line_width (cr, line_width);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_matrix (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_status_t status;
- cairo_matrix_t m;
- int type;
- check (2);
- status = _csi_ostack_get_matrix (ctx, 0, &m);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_set_matrix (obj->datum.cr, &m);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- cairo_pattern_set_matrix (obj->datum.pattern, &m);
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- obj->datum.matrix->matrix = m;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- struct _mime_tag {
- csi_t *ctx;
- csi_string_t *source;
- };
- static void
- _mime_tag_destroy (void *closure)
- {
- struct _mime_tag *tag = closure;
- if (--tag->source->base.ref)
- csi_string_free (tag->ctx, tag->source);
- _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag));
- }
- static csi_status_t
- _set_mime_data (csi_t *ctx)
- {
- csi_status_t status;
- csi_object_t *obj;
- const char *mime = NULL; /* silence the compiler */
- csi_object_t source;
- cairo_surface_t *surface;
- struct _mime_tag *tag;
- int type;
- check (3);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_FILE:
- status = _csi_file_as_string (ctx, obj->datum.file, &source);
- if (_csi_unlikely (status))
- return status;
- break;
- case CSI_OBJECT_TYPE_STRING:
- source = *csi_object_reference (obj);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- status = _csi_ostack_get_string_constant (ctx, 1, &mime);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 2, &surface);
- if (_csi_unlikely (status))
- return status;
- /* XXX free source */
- tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag));
- if (_csi_unlikely (tag == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- tag->ctx = cairo_script_interpreter_reference (ctx);
- tag->source = source.datum.string;
- tag->source->base.ref++;
- status = cairo_surface_set_mime_data (surface,
- mime,
- (uint8_t *)
- source.datum.string->string,
- source.datum.string->len,
- _mime_tag_destroy, tag);
- if (_csi_unlikely (status)) {
- _mime_tag_destroy (tag);
- return status;
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_miter_limit (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- double miter_limit;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &miter_limit);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_miter_limit (cr, miter_limit);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_operator (csi_t *ctx)
- {
- cairo_t *cr;
- long val;
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_integer (ctx, 0, &val);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_operator (cr, val);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_scaled_font (csi_t *ctx)
- {
- cairo_t *cr;
- cairo_scaled_font_t *font = NULL; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_scaled_font (ctx, 0, &font);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_scaled_font (cr, font);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_source (csi_t *ctx)
- {
- cairo_t *cr;
- cairo_pattern_t *pattern = NULL; /* silence the compiler */
- csi_status_t status;
- check (2);
- status = _csi_ostack_get_pattern (ctx, 0, &pattern);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_source (cr, pattern);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_boolean_t
- _matching_images (cairo_surface_t *a, cairo_surface_t *b)
- {
- cairo_format_t format_a, format_b;
- if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE)
- return FALSE;
- if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE)
- return FALSE;
- if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b))
- return FALSE;
- if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b))
- return FALSE;
- format_a = cairo_image_surface_get_format (a);
- if (format_a == CAIRO_FORMAT_RGB24)
- format_a = CAIRO_FORMAT_ARGB32;
- format_b = cairo_image_surface_get_format (b);
- if (format_b == CAIRO_FORMAT_RGB24)
- format_b = CAIRO_FORMAT_ARGB32;
- if (format_a != format_b)
- return FALSE;
- return TRUE;
- }
- static csi_status_t
- _set_source_image (csi_t *ctx)
- {
- csi_status_t status;
- cairo_surface_t *surface;
- cairo_surface_t *source;
- check (2);
- status = _csi_ostack_get_surface (ctx, 0, &source);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 1, &surface);
- if (_csi_unlikely (status))
- return status;
- /* Catch the most frequent use of simply uploading pixel data,
- * principally to remove the pixman ops from the profiles.
- */
- if (_csi_likely (_matching_images (surface, source))) {
- if (cairo_surface_get_reference_count (surface) == 1 &&
- cairo_surface_get_reference_count (source) == 1)
- {
- _csi_peek_ostack (ctx, 0)->datum.surface = surface;
- _csi_peek_ostack (ctx, 1)->datum.surface = source;
- }
- else
- {
- cairo_surface_flush (surface);
- memcpy (cairo_image_surface_get_data (surface),
- cairo_image_surface_get_data (source),
- cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
- cairo_surface_mark_dirty (surface);
- }
- } else {
- cairo_t *cr;
- cr = cairo_create (surface);
- cairo_set_source_surface (cr, source, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_source_rgb (csi_t *ctx)
- {
- csi_status_t status;
- double r,g,b;
- cairo_t *cr;
- check (4);
- status = _csi_ostack_get_number (ctx, 0, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 3, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_source_rgb (cr, r, g, b);
- pop (3);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_source_rgba (csi_t *ctx)
- {
- csi_status_t status;
- double r,g,b,a;
- cairo_t *cr;
- check (5);
- status = _csi_ostack_get_number (ctx, 0, &a);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &b);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &g);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &r);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 4, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_source_rgba (cr, r, g, b, a);
- pop (4);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _set_tolerance (csi_t *ctx)
- {
- csi_status_t status;
- cairo_t *cr;
- double tolerance;
- check (2);
- status = _csi_ostack_get_number (ctx, 0, &tolerance);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_set_tolerance (cr, tolerance);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _transform (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_status_t status;
- cairo_matrix_t m;
- int type;
- check (2);
- status = _csi_ostack_get_matrix (ctx, 0, &m);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_transform (obj->datum.cr, &m);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- {
- cairo_matrix_t ctm;
- cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
- cairo_matrix_multiply (&ctm, &m, &ctm);
- cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
- }
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- cairo_matrix_multiply (&obj->datum.matrix->matrix,
- &m,
- &obj->datum.matrix->matrix);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _translate (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_status_t status;
- double x, y;
- int type;
- check (3);
- status = _csi_ostack_get_number (ctx, 0, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &x);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 2);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_translate (obj->datum.cr, x, y);
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- {
- cairo_matrix_t ctm;
- cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
- cairo_matrix_translate (&ctm, x, y);
- cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
- }
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- cairo_matrix_translate (&obj->datum.matrix->matrix, x, y);
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _true (csi_t *ctx)
- {
- return _csi_push_ostack_boolean (ctx, TRUE);
- }
- static csi_status_t
- _show_page (csi_t *ctx)
- {
- csi_object_t *obj;
- int type;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_CONTEXT:
- cairo_show_page (obj->datum.cr);
- if (ctx->hooks.copy_page != NULL)
- ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
- break;
- case CSI_OBJECT_TYPE_SURFACE:
- cairo_surface_show_page (obj->datum.surface);
- /* XXX hook? */
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _similar (csi_t *ctx)
- {
- csi_object_t obj;
- long content;
- double width, height;
- cairo_surface_t *other;
- csi_status_t status;
- check (4);
- status = _csi_ostack_get_integer (ctx, 0, &content);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &height);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 3, &other);
- if (_csi_unlikely (status))
- return status;
- /* silently fix-up a common bug when writing CS */
- if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) {
- if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- switch ((int) content) {
- default:
- case CAIRO_FORMAT_ARGB32:
- content = CAIRO_CONTENT_COLOR_ALPHA;
- break;
- case CAIRO_FORMAT_RGB16_565:
- case CAIRO_FORMAT_RGB24:
- content = CAIRO_CONTENT_COLOR;
- break;
- case CAIRO_FORMAT_A8:
- case CAIRO_FORMAT_A1:
- content = CAIRO_CONTENT_ALPHA;
- break;
- }
- }
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_create_similar (other,
- content, width, height);
- pop (4);
- return push (&obj);
- }
- static csi_status_t
- _similar_image (csi_t *ctx)
- {
- csi_object_t obj;
- long format;
- double width, height;
- cairo_surface_t *other;
- csi_status_t status;
- check (4);
- status = _csi_ostack_get_number (ctx, 0, &height);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 2, &format);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 3, &other);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_create_similar_image (other,
- format,
- width, height);
- pop (4);
- return push (&obj);
- }
- static csi_status_t
- _subsurface (csi_t *ctx)
- {
- csi_object_t obj;
- double x, y, width, height;
- cairo_surface_t *target;
- csi_status_t status;
- check (5);
- status = _csi_ostack_get_number (ctx, 0, &height);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 1, &width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 2, &y);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_number (ctx, 3, &x);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 4, &target);
- if (_csi_unlikely (status))
- return status;
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height);
- pop (5);
- return push (&obj);
- }
- static csi_status_t
- _show_text (csi_t *ctx)
- {
- csi_status_t status;
- csi_string_t *text;
- cairo_t *cr;
- check (2);
- status = _csi_ostack_get_string (ctx, 0, &text);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_show_text (cr, text->string);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _show_glyphs (csi_t *ctx)
- {
- csi_array_t *array;
- csi_status_t status;
- cairo_t *cr;
- cairo_glyph_t stack_glyphs[256], *glyphs;
- csi_integer_t nglyphs, i;
- check (2);
- status = _csi_ostack_get_array (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- /* count glyphs */
- nglyphs = 0;
- for (i = 0; i < array->stack.len; i++) {
- csi_object_t *obj = &array->stack.objects[i];
- int type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_ARRAY:
- nglyphs += obj->datum.array->stack.len;
- break;
- case CSI_OBJECT_TYPE_STRING:
- nglyphs += obj->datum.string->len;
- break;
- }
- }
- if (nglyphs == 0) {
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
- if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
- if (_csi_unlikely (glyphs == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else
- glyphs = stack_glyphs;
- nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- cairo_show_glyphs (cr, glyphs, nglyphs);
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _show_text_glyphs (csi_t *ctx)
- {
- csi_object_t *obj;
- csi_array_t *array;
- csi_string_t *string;
- csi_string_t *utf8_string;
- csi_status_t status;
- cairo_t *cr;
- cairo_text_cluster_t stack_clusters[256], *clusters;
- cairo_glyph_t stack_glyphs[256], *glyphs;
- csi_integer_t nglyphs, nclusters, i;
- long direction;
- int type;
- check (5);
- status = _csi_ostack_get_integer (ctx, 0, &direction);
- if (_csi_unlikely (status))
- return status;
- obj = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_ARRAY:
- array = obj->datum.array;
- nclusters = array->stack.len / 2;
- if (nclusters > ARRAY_LENGTH (stack_clusters)) {
- if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
- if (_csi_unlikely (clusters == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else
- clusters = stack_clusters;
- for (i = 0; i < nclusters; i++) {
- clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]);
- clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]);
- }
- break;
- case CSI_OBJECT_TYPE_STRING:
- string = obj->datum.string;
- nclusters = string->len / 2;
- if (nclusters > ARRAY_LENGTH (stack_clusters)) {
- if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
- if (_csi_unlikely (clusters == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else
- clusters = stack_clusters;
- for (i = 0; i < nclusters; i++) {
- clusters[i].num_bytes = string->string[2*i+0];
- clusters[i].num_glyphs = string->string[2*i+1];
- }
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- status = _csi_ostack_get_array (ctx, 2, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_string (ctx, 3, &utf8_string);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 4, &cr);
- if (_csi_unlikely (status))
- return status;
- /* count glyphs */
- nglyphs = 0;
- for (i = 0; i < array->stack.len; i++) {
- obj = &array->stack.objects[i];
- type = csi_object_get_type (obj);
- switch (type) {
- case CSI_OBJECT_TYPE_ARRAY:
- nglyphs += obj->datum.array->stack.len;
- break;
- case CSI_OBJECT_TYPE_STRING:
- nglyphs += obj->datum.string->len;
- break;
- }
- }
- if (nglyphs == 0) {
- pop (4);
- return CSI_STATUS_SUCCESS;
- }
- if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
- if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
- if (_csi_unlikely (glyphs == NULL))
- return _csi_error (CSI_STATUS_NO_MEMORY);
- } else
- glyphs = stack_glyphs;
- nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- cairo_show_text_glyphs (cr,
- utf8_string->string, utf8_string->len,
- glyphs, nglyphs,
- clusters, nclusters,
- direction);
- if (clusters != stack_clusters)
- _csi_free (ctx, clusters);
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
- pop (4);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _stroke (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_stroke);
- }
- static csi_status_t
- _stroke_preserve (csi_t *ctx)
- {
- return _do_cairo_op (ctx, cairo_stroke_preserve);
- }
- static csi_status_t
- _sub (csi_t *ctx)
- {
- csi_object_t *A;
- csi_object_t *B;
- csi_object_type_t type_a, type_b;
- check (2);
- B = _csi_peek_ostack (ctx, 0);
- A = _csi_peek_ostack (ctx, 1);
- type_a = csi_object_get_type (A);
- if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
- type_a == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- type_b = csi_object_get_type (B);
- if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
- type_b == CSI_OBJECT_TYPE_REAL)))
- {
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (2);
- if (type_a == CSI_OBJECT_TYPE_REAL &&
- type_b == CSI_OBJECT_TYPE_REAL)
- {
- return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real);
- }
- else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
- type_b == CSI_OBJECT_TYPE_INTEGER)
- {
- return _csi_push_ostack_integer (ctx,
- A->datum.integer - B->datum.integer);
- }
- else
- {
- double v;
- if (type_a == CSI_OBJECT_TYPE_REAL)
- v = A->datum.real;
- else
- v = A->datum.integer;
- if (type_b == CSI_OBJECT_TYPE_REAL)
- v -= B->datum.real;
- else
- v -= B->datum.integer;
- return _csi_push_ostack_real (ctx, v);
- }
- }
- static csi_status_t
- _surface (csi_t *ctx)
- {
- csi_object_t obj;
- csi_dictionary_t *dict;
- csi_proxy_t *proxy;
- csi_object_t key;
- double width, height;
- csi_surface_create_func_t hook;
- long content;
- cairo_surface_t *surface;
- long uid;
- csi_status_t status;
- check (1);
- status = _csi_ostack_get_dictionary (ctx, 0, &dict);
- if (_csi_unlikely (status))
- return status;
- status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width);
- if (_csi_unlikely (status))
- return status;
- status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height);
- if (_csi_unlikely (status))
- return status;
- content = CAIRO_CONTENT_COLOR_ALPHA;
- status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content);
- if (_csi_unlikely (status))
- return status;
- uid = 0;
- status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid);
- if (_csi_unlikely (status))
- return status;
- if (uid == 0) {
- status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid);
- if (_csi_unlikely (status))
- return status;
- }
- hook = ctx->hooks.surface_create;
- assert (hook != NULL);
- surface = hook (ctx->hooks.closure, content, width, height, uid);
- if (_csi_unlikely (surface == NULL)) {
- return _csi_error (CSI_STATUS_NULL_POINTER);
- }
- proxy = _csi_proxy_create (ctx, surface, dict,
- ctx->hooks.surface_destroy,
- ctx->hooks.closure);
- if (_csi_unlikely (proxy == NULL)) {
- cairo_surface_destroy (surface);
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
- status = cairo_surface_set_user_data (surface,
- &_csi_proxy_key,
- proxy, _csi_proxy_destroy);
- if (_csi_unlikely (status)) {
- _csi_proxy_destroy (proxy);
- cairo_surface_destroy (surface);
- return status;
- }
- status = csi_name_new_static (ctx, &key, "fallback-resolution");
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- if (csi_dictionary_has (dict, key.datum.name)) {
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
- csi_array_t *array = obj.datum.array;
- if (array->stack.len == 2) {
- cairo_surface_set_fallback_resolution (surface,
- csi_number_get_value
- (&array->stack.objects[0]),
- csi_number_get_value
- (&array->stack.objects[1]));
- }
- }
- }
- /* initialise surface to source */
- status = csi_name_new_static (ctx, &key, "source");
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- if (csi_dictionary_has (dict, key.datum.name)) {
- cairo_surface_t *image;
- cairo_t *cr;
- status = _image_load_from_dictionary (ctx, dict, &image);
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- cr = cairo_create (surface);
- cairo_set_source_surface (cr, image, 0, 0);
- cairo_surface_destroy (image);
- cairo_paint (cr);
- status = cairo_status (cr);
- cairo_destroy (cr);
- if (_csi_unlikely (status))
- return status;
- }
- status = csi_name_new_static (ctx, &key, "device-offset");
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- if (csi_dictionary_has (dict, key.datum.name)) {
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
- csi_array_t *array = obj.datum.array;
- if (array->stack.len == 2) {
- cairo_surface_set_device_offset (surface,
- csi_number_get_value
- (&array->stack.objects[0]),
- csi_number_get_value
- (&array->stack.objects[1]));
- }
- }
- }
- status = csi_name_new_static (ctx, &key, "device-scale");
- if (_csi_unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
- if (csi_dictionary_has (dict, key.datum.name)) {
- status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
- if (_csi_unlikely (status))
- return status;
- if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
- csi_array_t *array = obj.datum.array;
- if (array->stack.len == 2) {
- cairo_surface_set_device_scale (surface,
- csi_number_get_value
- (&array->stack.objects[0]),
- csi_number_get_value
- (&array->stack.objects[1]));
- }
- }
- }
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = surface;
- pop (1);
- return push (&obj);
- }
- static csi_status_t
- _record (csi_t *ctx)
- {
- csi_object_t obj;
- long content;
- csi_array_t *array;
- csi_status_t status;
- cairo_rectangle_t extents;
- cairo_rectangle_t *r;
- check (2);
- status = _csi_ostack_get_array (ctx, 0, &array);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_integer (ctx, 1, &content);
- if (_csi_unlikely (status))
- return status;
- switch (array->stack.len) {
- case 0:
- r = NULL;
- break;
- case 2:
- extents.x = extents.y = 0;
- extents.width = _csi_object_as_real (&array->stack.objects[0]);
- extents.height = _csi_object_as_real (&array->stack.objects[1]);
- r = &extents;
- break;
- case 4:
- extents.x = _csi_object_as_real (&array->stack.objects[0]);
- extents.y = _csi_object_as_real (&array->stack.objects[1]);
- extents.width = _csi_object_as_real (&array->stack.objects[2]);
- extents.height = _csi_object_as_real (&array->stack.objects[3]);
- r = &extents;
- break;
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- obj.type = CSI_OBJECT_TYPE_SURFACE;
- obj.datum.surface = cairo_recording_surface_create (content, r);
- pop (2);
- return push (&obj);
- }
- static csi_status_t
- _text_path (csi_t *ctx)
- {
- csi_status_t status;
- csi_string_t *text;
- cairo_t *cr;
- check (2);
- status = _csi_ostack_get_string (ctx, 0, &text);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_context (ctx, 1, &cr);
- if (_csi_unlikely (status))
- return status;
- cairo_text_path (cr, text->string);
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _undef (csi_t *ctx)
- {
- csi_name_t name = 0; /* silence the compiler */
- csi_status_t status;
- check (1);
- status = _csi_ostack_get_name (ctx, 0, &name);
- if (_csi_unlikely (status))
- return status;
- status = _csi_name_undefine (ctx, name);
- if (_csi_unlikely (status))
- return status;
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _unset (csi_t *ctx)
- {
- csi_object_t *dst;
- csi_name_t name = 0; /* silence the compiler */
- csi_status_t status;
- int type;
- check (2);
- status = _csi_ostack_get_name (ctx, 0, &name);
- if (_csi_unlikely (status))
- return status;
- dst = _csi_peek_ostack (ctx, 1);
- type = csi_object_get_type (dst);
- switch (type) {
- case CSI_OBJECT_TYPE_DICTIONARY:
- csi_dictionary_remove (ctx, dst->datum.dictionary, name);
- break;
- case CSI_OBJECT_TYPE_STRING:
- case CSI_OBJECT_TYPE_ARRAY:
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _write_to_png (csi_t *ctx)
- {
- csi_status_t status;
- csi_string_t *filename;
- cairo_surface_t *surface;
- check (2);
- status = _csi_ostack_get_string (ctx, 0, &filename);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 1, &surface);
- if (_csi_unlikely (status))
- return status;
- #if CAIRO_HAS_PNG_FUNCTIONS
- status = cairo_surface_write_to_png (surface, filename->string);
- if (_csi_unlikely (status))
- return status;
- #else
- return CAIRO_STATUS_WRITE_ERROR;
- #endif
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _write_to_script (csi_t *ctx)
- {
- csi_status_t status;
- csi_string_t *filename;
- cairo_surface_t *record;
- check (2);
- status = _csi_ostack_get_string (ctx, 0, &filename);
- if (_csi_unlikely (status))
- return status;
- status = _csi_ostack_get_surface (ctx, 1, &record);
- if (_csi_unlikely (status))
- return status;
- if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING)
- return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
- #if CAIRO_HAS_SCRIPT_SURFACE
- {
- cairo_device_t *script;
- script = cairo_script_create (filename->string);
- status = cairo_script_from_recording_surface (script, record);
- cairo_device_destroy (script);
- if (_csi_unlikely (status))
- return status;
- }
- #else
- return CAIRO_STATUS_WRITE_ERROR;
- #endif
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static csi_status_t
- _xor (csi_t *ctx)
- {
- csi_object_t *a, *b;
- int type;
- check (2);
- a = _csi_peek_ostack (ctx, 0);
- b = _csi_peek_ostack (ctx, 1);
- if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- pop (2);
- type = csi_object_get_type (a);
- switch (type) {
- case CSI_OBJECT_TYPE_INTEGER:
- return _csi_push_ostack_integer (ctx,
- a->datum.integer ^ b->datum.integer);
- case CSI_OBJECT_TYPE_BOOLEAN:
- return _csi_push_ostack_boolean (ctx,
- a->datum.boolean ^ b->datum.boolean);
- default:
- return _csi_error (CSI_STATUS_INVALID_SCRIPT);
- }
- }
- static csi_status_t
- _debug_print (csi_t *ctx)
- {
- csi_object_t *obj;
- check (1);
- obj = _csi_peek_ostack (ctx, 0);
- switch (csi_object_get_type (obj)) {
- case CSI_OBJECT_TYPE_NULL:
- fprintf (stderr, "NULL\n");
- break;
- /* atomics */
- case CSI_OBJECT_TYPE_BOOLEAN:
- fprintf (stderr, "boolean: %s\n",
- obj->datum.boolean ? "true" : "false");
- break;
- case CSI_OBJECT_TYPE_INTEGER:
- fprintf (stderr, "integer: %ld\n", obj->datum.integer);
- break;
- case CSI_OBJECT_TYPE_MARK:
- fprintf (stderr, "mark\n");
- break;
- case CSI_OBJECT_TYPE_NAME:
- fprintf (stderr, "name: %s\n", (char *) obj->datum.name);
- break;
- case CSI_OBJECT_TYPE_OPERATOR:
- fprintf (stderr, "operator: %p\n", obj->datum.ptr);
- break;
- case CSI_OBJECT_TYPE_REAL:
- fprintf (stderr, "real: %g\n", obj->datum.real);
- break;
- /* compound */
- case CSI_OBJECT_TYPE_ARRAY:
- fprintf (stderr, "array\n");
- break;
- case CSI_OBJECT_TYPE_DICTIONARY:
- fprintf (stderr, "dictionary\n");
- break;
- case CSI_OBJECT_TYPE_FILE:
- fprintf (stderr, "file\n");
- break;
- case CSI_OBJECT_TYPE_MATRIX:
- fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n",
- obj->datum.matrix->matrix.xx,
- obj->datum.matrix->matrix.yx,
- obj->datum.matrix->matrix.xy,
- obj->datum.matrix->matrix.yy,
- obj->datum.matrix->matrix.x0,
- obj->datum.matrix->matrix.y0);
- break;
- case CSI_OBJECT_TYPE_STRING:
- fprintf (stderr, "string: %s\n", obj->datum.string->string);
- break;
- /* cairo */
- case CSI_OBJECT_TYPE_CONTEXT:
- fprintf (stderr, "context\n");
- break;
- case CSI_OBJECT_TYPE_FONT:
- fprintf (stderr, "font\n");
- break;
- case CSI_OBJECT_TYPE_PATTERN:
- fprintf (stderr, "pattern\n");
- break;
- case CSI_OBJECT_TYPE_SCALED_FONT:
- fprintf (stderr, "scaled-font\n");
- break;
- case CSI_OBJECT_TYPE_SURFACE:
- fprintf (stderr, "surface\n");
- break;
- }
- pop (1);
- return CSI_STATUS_SUCCESS;
- }
- static const csi_operator_def_t
- _defs[] = {
- { "<<", _mark },
- { ">>", end_dict_construction },
- { "[", _mark },
- { "]", end_array_construction },
- { "a", _alpha },
- { "abs", NULL },
- { "add", _add },
- { "add-color-stop", _add_color_stop },
- { "and", _and },
- { "arc", _arc },
- { "arc-negative", _arc_negative },
- { "arc-", _arc_negative },
- { "arc-to", NULL },
- { "array", _array },
- { "astore", NULL },
- { "atan", NULL },
- { "bind", _bind },
- { "bitshift", _bitshift },
- { "c", _curve_to },
- { "C", _rel_curve_to },
- { "ceiling", NULL },
- { "clear", NULL },
- { "clear-to-mark", NULL },
- { "clip", _clip },
- { "clip-extents", NULL },
- { "clip-preserve", _clip_preserve },
- { "clip+", _clip_preserve },
- { "close-path", _close_path },
- { "context", _context },
- { "copy", _copy },
- { "copy-page", _copy_page },
- { "cos", NULL },
- { "count", NULL },
- { "count-to-mark", NULL },
- { "curve-to", _curve_to },
- { "cvi", _cvi },
- { "cvr", _cvr },
- { "def", _def },
- { "device-to-user", NULL },
- { "device-to-user-distance", NULL },
- { "dict", _dict },
- { "div", _div },
- { "dup", _duplicate },
- { "eq", _eq },
- { "exch", _exch },
- { "exec", NULL },
- { "exp", NULL },
- { "false", _false },
- { "fill", _fill },
- { "fill-extents", NULL },
- { "fill-preserve", _fill_preserve },
- { "fill+", _fill_preserve },
- { "filter", _filter },
- { "floor", NULL },
- { "font", _font },
- { "for", _for },
- { "forall", NULL },
- { "g", _gray },
- { "ge", _ge },
- { "get", _get },
- { "glyph-path", _glyph_path },
- { "gt", _gt },
- { "h", _close_path },
- { "identity", _identity },
- { "if", _if },
- { "ifelse", _ifelse },
- { "image", _image },
- { "index", _index },
- { "integer", _integer },
- { "invert", _invert },
- { "in-stroke", NULL },
- { "in-fill", NULL },
- { "known", NULL },
- { "l", _line_to },
- { "L", _rel_line_to },
- { "languagelevel", NULL },
- { "le", _le },
- { "length", NULL },
- { "linear", _linear },
- { "line-to", _line_to },
- { "ln", NULL },
- { "load", NULL },
- { "log", NULL },
- { "loop", NULL },
- { "lt", _lt },
- { "m", _move_to },
- { "M", _rel_move_to },
- { "map-to-image", _map_to_image },
- { "mark", _mark },
- { "mask", _mask },
- { "matrix", _matrix },
- { "mesh", _mesh },
- { "begin-patch", _mesh_begin_patch },
- { "end-patch", _mesh_end_patch },
- { "set-control-point", _mesh_set_control_point },
- { "set-corner-color", _mesh_set_corner_color },
- { "mod", _mod },
- { "move-to", _move_to },
- { "mul", _mul },
- { "multiply", NULL },
- { "n", _new_path },
- { "N", _new_sub_path },
- { "ne", _ne },
- { "neg", _neg },
- { "new-path", _new_path },
- { "new-sub-path", _new_sub_path },
- { "not", _not },
- { "null", _null },
- { "or", _or },
- { "paint", _paint },
- { "paint-with-alpha", _paint_with_alpha },
- { "pattern", _pattern },
- { "pop", _pop },
- { "pop-group", _pop_group },
- { "push-group", _push_group },
- { "radial", _radial },
- { "rand", NULL },
- { "record", _record },
- { "rectangle", _rectangle },
- { "repeat", _repeat },
- { "restore", _restore },
- { "rel-curve-to", _rel_curve_to },
- { "rel-line-to", _rel_line_to },
- { "rel-move-to", _rel_move_to },
- { "reset-clip", _reset_clip },
- { "rgb", _rgb },
- { "rgba", _rgba },
- { "roll", _roll },
- { "rotate", _rotate },
- { "round", NULL },
- { "run", NULL },
- { "save", _save },
- { "scale", _scale },
- { "scaled-font", _scaled_font },
- { "select-font-face", _select_font_face },
- { "set", _set },
- { "set-antialias", _set_antialias },
- { "set-dash", _set_dash },
- { "set-device-offset", _set_device_offset },
- { "set-device-scale", _set_device_scale },
- { "set-extend", _set_extend },
- { "set-fallback-resolution", _set_fallback_resolution },
- { "set-fill-rule", _set_fill_rule },
- { "set-filter", _set_filter },
- { "set-font-face", _set_font_face },
- { "set-font-options", _set_font_options },
- { "set-font-matrix", _set_font_matrix },
- { "set-font-size", _set_font_size },
- { "set-line-cap", _set_line_cap },
- { "set-line-join", _set_line_join },
- { "set-line-width", _set_line_width },
- { "set-matrix", _set_matrix },
- { "set-miter-limit", _set_miter_limit },
- { "set-mime-data", _set_mime_data },
- { "set-operator", _set_operator },
- { "set-scaled-font", _set_scaled_font },
- { "set-source", _set_source },
- { "set-source-image", _set_source_image },
- { "set-source-rgb", _set_source_rgb },
- { "set-source-rgba", _set_source_rgba },
- { "set-tolerance", _set_tolerance },
- { "show-glyphs", _show_glyphs },
- { "show-text", _show_text },
- { "show-text-glyphs", _show_text_glyphs },
- { "show-page", _show_page },
- { "similar", _similar },
- { "similar-image", _similar_image },
- { "sin", NULL },
- { "sqrt", NULL },
- { "sub", _sub },
- { "subsurface", _subsurface },
- { "surface", _surface },
- { "string", NULL },
- { "stroke", _stroke },
- { "stroke-extents", NULL },
- { "stroke-preserve", _stroke_preserve },
- { "stroke+", _stroke_preserve },
- { "text-path", _text_path },
- { "transform", _transform },
- { "transform-distance", NULL },
- { "transform-point", NULL },
- { "translate", _translate },
- { "true", _true },
- { "type", NULL },
- { "undef", _undef },
- { "unmap-image", _unmap_image },
- { "unset", _unset },
- { "user-to-device", NULL },
- { "user-to-device-distance", NULL },
- { "where", NULL },
- { "write-to-png", _write_to_png },
- { "write-to-script", _write_to_script },
- { "xor", _xor },
- { "=", _debug_print },
- { NULL, NULL },
- };
- const csi_operator_def_t *
- _csi_operators (void)
- {
- return _defs;
- }
- static const csi_integer_constant_def_t
- _integer_constants[] = {
- { "CLEAR", CAIRO_OPERATOR_CLEAR },
- { "SOURCE", CAIRO_OPERATOR_SOURCE },
- { "OVER", CAIRO_OPERATOR_OVER },
- { "IN", CAIRO_OPERATOR_IN },
- { "OUT", CAIRO_OPERATOR_OUT },
- { "ATOP", CAIRO_OPERATOR_ATOP },
- { "DEST", CAIRO_OPERATOR_DEST },
- { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER },
- { "DEST_IN", CAIRO_OPERATOR_DEST_IN },
- { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT },
- { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP },
- { "XOR", CAIRO_OPERATOR_XOR },
- { "ADD", CAIRO_OPERATOR_ADD },
- { "SATURATE", CAIRO_OPERATOR_SATURATE },
- { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY },
- { "SCREEN", CAIRO_OPERATOR_SCREEN },
- { "OVERLAY", CAIRO_OPERATOR_OVERLAY },
- { "DARKEN", CAIRO_OPERATOR_DARKEN },
- { "LIGHTEN", CAIRO_OPERATOR_LIGHTEN },
- { "DODGE", CAIRO_OPERATOR_COLOR_DODGE },
- { "BURN", CAIRO_OPERATOR_COLOR_BURN },
- { "HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT },
- { "SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT },
- { "DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE },
- { "EXCLUSION", CAIRO_OPERATOR_EXCLUSION },
- { "HSL_HUE", CAIRO_OPERATOR_HSL_HUE },
- { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION },
- { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR },
- { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY },
- { "WINDING", CAIRO_FILL_RULE_WINDING },
- { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD },
- { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT },
- { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE },
- { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY },
- { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL },
- { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST },
- { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD },
- { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST },
- { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT },
- { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND },
- { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE },
- { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER },
- { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND },
- { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL },
- { "EXTEND_NONE", CAIRO_EXTEND_NONE },
- { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT },
- { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT },
- { "EXTEND_PAD", CAIRO_EXTEND_PAD },
- { "FILTER_FAST", CAIRO_FILTER_FAST },
- { "FILTER_GOOD", CAIRO_FILTER_GOOD },
- { "FILTER_BEST", CAIRO_FILTER_BEST },
- { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR },
- { "FILTER_NEAREST", CAIRO_FILTER_NEAREST },
- { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN },
- { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL },
- { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC },
- { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE },
- { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL },
- { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD },
- { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT },
- { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB },
- { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR },
- { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB },
- { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR },
- { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT },
- { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE },
- { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT },
- { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM },
- { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL },
- { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT },
- { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF },
- { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON },
- { "FORWARD", 0 },
- { "BACKWARD", 1 },
- { "COLOR", CAIRO_CONTENT_COLOR },
- { "ALPHA", CAIRO_CONTENT_ALPHA },
- { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA },
- { "A1", CAIRO_FORMAT_A1 },
- { "A8", CAIRO_FORMAT_A8 },
- { "RGB16_565", CAIRO_FORMAT_RGB16_565 },
- { "RGB24", CAIRO_FORMAT_RGB24 },
- { "ARGB32", CAIRO_FORMAT_ARGB32 },
- { "INVALID", CAIRO_FORMAT_INVALID },
- { NULL, 0 }
- };
- const csi_integer_constant_def_t *
- _csi_integer_constants (void)
- {
- return _integer_constants;
- }
- static const csi_real_constant_def_t
- _real_constants[] = {
- { "math.pi", M_PI },
- { "math.2pi", 2 * M_PI },
- { "math.sqrt2", M_SQRT2 },
- { "math.ln2", M_LN2 },
- { NULL, 0 }
- };
- const csi_real_constant_def_t *
- _csi_real_constants (void)
- {
- return _real_constants;
- }
|