From a2cd536676dd8eb3a6229fbd1ea20e56e2075835 Mon Sep 17 00:00:00 2001 From: Curtis Hard Date: Sat, 11 Apr 2015 13:38:21 +0100 Subject: [PATCH] Loads of fixes for rendering Fixes for rendering and improves feature set for complicated SVG's --- .../UserInterfaceState.xcuserstate | Bin 41841 -> 41841 bytes source/IJSVG.h | 1 + source/IJSVG.m | 56 ++++++++++------ source/IJSVGCommand.h | 3 + source/IJSVGCommand.m | 6 ++ source/IJSVGCommandArc.m | 22 +++++- source/IJSVGGradient.m | 7 ++ source/IJSVGLinearGradient.m | 4 ++ source/IJSVGNode.h | 3 + source/IJSVGNode.m | 63 ++++++++++-------- source/IJSVGParser.h | 2 + source/IJSVGParser.m | 58 ++++++++++++++++ source/IJSVGRadialGradient.m | 4 ++ source/IJSVGUtils.m | 2 +- 14 files changed, 181 insertions(+), 50 deletions(-) diff --git a/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate b/IJSVGExample/IJSVGExample.xcodeproj/project.xcworkspace/xcuserdata/curtishard.xcuserdatad/UserInterfaceState.xcuserstate index 0b5c905597f5b199a250ef8cce6726ae5aea4adb..42d23894f06c6f28dc5be79d6e8e5b19e19f7bd2 100644 GIT binary patch delta 16150 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 delta 16091 zcmajF2V7Iv`#*lqy-^eh2`dmF2_(!Qn}C2M?4|4#Rsw-6NZ5Pbdl_!)xb6*Zt=3ho ztJb>e-qumK)z)gYR;||cyGc;t`|0cd_w|yTd*09UoM)W#+~+yTUq|4-j=(e8Q7Kdm zHA5{>E7S(HLmf~jghCjELtW5U&~#`9G!vQyErpgr%b`A~A6fyegw{YCpe@i=XeYEE z`T;rs{Rka|4nwD))6f~{JahrN3SEP4LwBHu&~MOl=x^u+^b&dlOn@n%0y97ZbYKoF zfFfEeTfDJTYIKn2vG98`lk z&;*(R2Bv_SU;$VHmV#wq1y~8zf^}dc*aWtMZD1$(4(tOzf}`LBI14U=pTTwT3%Cs? zf&1VQ_yarxuL1f7{0qY{0#jg9m~;ra3eeso&?W<=fd;g`S4PBHM}0)1aF0R zz`Nl+@P7CQ_z?UPd<;GXUx2Tm@NM`Gd>4KM{{g>&|ApVe@8I|F2gD4aA#}tXu|O;l zE5r`5N1PBY;*IzqzK9xc#^4|x^T$CFHU|?FB*w&MmB_}G$mALVm{^(>krT0H>iVkM$Xa;`;bqc?O6iQq zx;k}TeMx1#0je8U(o)q>UzC`XnG>H@Qd=jl_12EO0F8u7VeVKQ)jRpLLc<>6WB=F>*yogQh-4E^AQgm6Vt=P4YE*m9lE(a$>TnKXKmFg9tNq zLFt*QswO?DQm!}Yla}4kM96(5)C2WG{F?>mNU_pKtI+a#fi;FGHCu5@_z(fj*R3-fngh*+=3(BL z59W*ct%P`_y^A1M(yRb1khD}lys&Jt9YH6Lw$6#GAi;8sb{-0bMnh|%b%Z0;)^jbi z9ttZ=$&68#)~l;3OKMv_8S^!?33Bg)He$hj&^Op%0X-=Qav#R}*V^au19 z8;gy@l2<@~l3sm=rI7NQNZpPyO0u9=kf0Cx2TR3hpBVoIFyy`ldJDaS-a{Xtj{pJy zOT*H!3@j7N!m_cPH2?t=FboU_MqmUOiREHqtQf1q%CLH@fmE*DW(HwHbK(Olz=SMT z0&BnkHoz9k!}75LtZ*f;1NIOPu&^RbLPl6h>H@Och#NEuPF`DJfFO93qi@G0;0D|w z6W{^(z!QuDUceiwAz1W`kyV%stHnyN0HT>5oCEwJ!72~{0)YSofncl@Q(|hY0@IQf zflv@eiZBAeY>M48j_*YJphMS1Q8t^ z#Z`K!`+uXjUJvyCN0bcv>l-~j;XiOg6u0Z5h)pttD@>u*$U}X6e6q>+0>K*ZM%=a^ zfe!W3F49jEp%p*^t-z*`p&&3r-UHu5f_~D$9i(HYVzi-52X(F;V48-Jj{U^+lP*@r zu&@3vgM9(5E5_+n@Q&2T9RajCHm3u?*cHGc13U6 zES+h@xtQ>Qt#$+4Bo46o-x>}UH?z#VXx;BZ{YiF*W#<6{AS1rN#G1s-7Y`oM44 ze0@r`^Lb2WWbg$1i7mhuf6mC@FYsb;b_FlND{LXQh|C(#tnHa^!G|H}M;OAEU`t8V znZdP#hruHt_kMUdnLL+c@%`{f*cj`>`pE^08FtAq4Ytt1bTW&sz!LjmOV|oqiT#KP z@**|$^4iLhdig+Jgl%C5GNHmu*bcVGR$;5LH7j5iR0DIcwPfUf7)YqF3$&vTcE#3x z)*tqO{m6t0^I=bT6zm0i!#=PtwjSGneT{9zHeugjo7cepZ~z<#3*aC)7#@vn!M0+% zvAx(n?0am#KB2DR!_ja8nM~mrI2MkB62-z zX!n)s$*cY`6Sw(}at!nz-I1dk49%(o@rCn0$9K=?_!2qHSf?*J;)*^W%+jAjxJ+lE z96NwT5qp^&R1ItY$1jznU#hW#q+c#!LIYPFxeMWX?9k^I4cr8y|G$30U>xp(yTL-z zFXOSp*b(eFc7Z(M-(web1rM{jfylSxpp)V0|LL0<@J!M-1a=hriS*4eOvsDWJLV~^ zuuTv$I%t%mzaTK6Bd;wuc(mXD@ejNJUO145&SNJAB_enknTX)!a39D^dFh$)6}4h^J!{Ot{Iquck0v2x&M#!GV*hNA%3$T#rYDq?fSS)GDP68 zE&@le%Vf^BMo0SwbaZ^$+Q;D&ko)rGnBddIY51(Jw9r*d@Hy-%CNN02NS;sl5_}oE zhTZtGzpui-3_gMI4frN@9s30nrtu=$pFz5RpXA=`B)`sO#Z0SFIqCktQ18F2yY5jX5F>^atp{jHneBc6ye zIq?E}MgA3}N$KW;ONT7-?O!KOtF0<)D6Ov>a4h1F2*^B!1R%~R_7eN6pOmAMLGnxK z^vs6p>Z;m$b*0iVj(quiW(q?@koyY68LUDANYZZXCHa6v>N)?>@qUsXizMizJA>uq zEIvdyqfM7s0{jIXqa54(1tFt|+gvj=1xfqtnRM)5O!!Gs7LxPXIl0)|FH7Vjg}N8Q zdaSn(DZ<`;0g4fs4p@bC_aUX&`!9e3QR#r?7~Y4du@7GW4T4tckcC)hpWc?wcGM#E zpVex>0rW+$W~61v2|(JB9x^#09Y`mFA{c@rT}U?$U>qPgpx|H_4u<2v2nQq9AiZRF z#)DjuNxF^&C+lGc9=Veoa9~WnHp$k7jKKfhQc^mHILBiUX3i$WS)LnkBA;xCT<2uK z)6e@lQ*-o34w(b(SdK-dee&M|WVvo%FGLn0i;*SBQe+tpOmRTPff){HIH2Red^NeR z`^ie5hpd98=z3WTGIfw2o@B=+AbMOJ30Ie5g6hJI{3P`o2I@x#@nw#F^kJXyL%Li`8lp?KpXQz!<~*)9^$|U2fjG)!vX2^02~D3K(G$tQ7DvQl;Py( z2nv~bC?>j)1mPeU2cvbv5FCW+KEp__9&Exia$l5&(M|w{VyemLTV_& zK?IrJ-1yG+V<@7**`5+XAq7O?AezJ#e2#q_C2Y^NSRBNW_;Qjzjgm>`5=uHH z0|yB>NbJ{bEZv48?S9X9ChqXrAb^OB8AYTrhZCiq<9ur<6%-9cOR1z(QL4$4MxHJl zcbcxrHOQapXC9>~uFew>;&5LLNIe;;e-OQRelth2R4C{8FSW(!CUk zWbZ0Ew1~2jvI-*uRE7gNslZ8Z9zpkUBA$?+=|0xU1}A@w9OR~8QaGAjs)b8yoxZVTqR$u zlxvjhIH<=#3t3oI`#F$f`~#2zkWUExSCQQJ{TH)q zhB=U@y=E8(${?Krz9RQ7`7u*>fhDE0h+6?nVsAhdF*eYdSQOx5uD5BJ2YL2}@o_Mn zTnr1G1VcLr6Tw0dwQaTFwGk3T_DN5&13o}-@wQ4xdY3iNYn zQDK8tEH+3zL@bNu6LbqxV#aui^%sTojV%t2Na;aDiT^0VHrjL$bGd=}C!M-h0p8ld z>Q?C&TO1ueh`!!HfAZ5}%%LnT2Ke-+9$gzVVi0qu0X<7N#`)S*X{yLe!ollx>(@IS z6E(=-iTXKCtZ>lWH2s_=Hh++nvkaoINa=n$D;eaS;85Z7^h~U{ut7|V4NSj$(sp^= zU~T&h=uN_}M`%4HTB{AnZQ^uFp!E_e~;M-DRim;w4zN*}G? z4X2}xh{{BxLCmKO6wgSrBL^{FFiby}(&I_S2!fR~SggKV!odrjSl!)BWzt}gHw?V5 z1~%CcU*6SW#FM0)K`J~n(EqE~|NHdeL(j@%J;&m)34^rz%fRtLN*C+3+muS>c%{|K z73ya1>e3+#zS5Jzy5@b%(BQo_Ah14of+4{(BEOm;Ga5`Go+YJO3=X-`FdahR$x&a_ zF)}t#kC4(M_3l_Y!H6B*P}?XU5<4TBfz0^J{u?%AqZwHl2uufUnIUU4^=qF<2_3XH z+rUGY(v$SA$WI+~-i>$$)IuMMz@h56>!saHjrnrcjJ))7erbcwnvuUjhON#zT}C;X zX7eR@M!^Quj<}O5v>l@D7z5%UrTdb6Zmf*h$e831e$XZ}iZeit zQhK0nUFN_S4TGa=G*(ALIA!Dy(kRWq=d4RR#J-FXgPfIZfLsTsjUn>#_3|7t2iq?- zF!7~yZ@nHvy;x>IM-8CFyUf7h{x}>+zH32tE3r9itnP7){_%)zNPeZDzYI>ui8O=9 z;cyZTk0oE~y9TB$a#=3_bDwPVozX7c6$lO|<8aCVbyn^ey?`tn&K@LyDUQ@FlSj%c z7ANb5MdWasI7K(ql>oY%=&rnRx<~E6V`{!ZmnxjR)G+9>G(T2H(L6v=R^au&YK;gV zAvCDfio-SZXss43DbJBu9dHw@>J zLkkJt^?%$kV(kdB+#In1hv(z)0!h9IhzN(ygTn+WTVt0td*U&a-Dr zl61&n^3hQit2h5B4(l#wbi{SCF#XhV96m8HwO6KJ>kNqwFOAWomvHh1;>(t}P^ypU zHIl-vOs~RSa;V!~56krKdq6&pmg^(>=Kw-c=n0>bkGY27D{{DA@gE)-`E=wng9l#Y zuny(lK!mBB;AONAcwxHM4eXqiE$!_l5)?e|G9ZIUTVCIRILw3csSW- zlcX+~VBmsHy5T=A*oYJ5K{|;Zq(q|%-M&C{cQ(?B6dF17(=qSbP4DFGeMzL`Fo{bQ zT)kyvp&vM)-7t;r^dP#g@X|E85F)zNvBEHnAcwCsx`T}9vPhD4iuK?++$2b!i;#GN zR-0-yD9f6J8GuB>r!LieFc6^wh>ew*U)}*GvHCe$Ro0ipX_90RkSe85BXb~==xnGT zvOuZfn zJDrU8I5K&N3{zkV>nYQkJBRc#ruw>rxZOO(y2jMTlsss2ab&*E`Z+kVjNC_9%irXp z^{quDo8j`#G|Y62;kJml*BVKJE^TYczo*;m$e!)@Hm$YphXv#={0>KU;pCkOvWM($ zh1)9H8RV}|$e#5F9Jxu}_6dk-9hJJq>wSkkh$5Js-nypMmH4xZO{hCJk`irD5&1V4 zjR%5l%h2CoyA0C@rVq&<0%YLGHH_5nI*!~R`#iGKBl^1b48Ky{*7?|$kacry{QW`& zLG(xZX3z9rve|>E!^j@ZQ)S$CPHPkQ2 zi~p%Ssrsq~M_zsEsu)9xPpYASL0*4?hjw^WLlJ}gJE-FOa#E@K3I<2seL|Ba45|mI zhFS*sKr9;@HKg{W8tNDdL?W?+#Hsb?lmbiXVfxbcw!IONIq@j^%=o$S2NQD>j!CMC z%w(p?Qj;wvKbTxKd1&&R$xBmXQ&UqjQ@W{zsg)_i)YjC_)WMW(8el3g4K@uSH&?i+ z$TZS4+BDWQ-ZarvYT9htZ93C*t?4$?qoy~hfNDi`qVlPusNPgxsz2%MaMIC{)M#of zHHE66)==9}>O|^HDnXq?okv|j?WeA!uBNV~uBU!YJx+aSW^BeYb2f7|^D*-^^EV4K zOE(jn$<1ob8qAu^TFu(cI?ZO8Eizkf)^E1bY_-`ov+vAyo9#6_V0O^#u-Q?wOJ={B z{blwq4WW&oS<~!j4m386M{}XM(L87Yv@x_;S{4m0pcT=|XWG&!Jb+o9M0d zc6uj$3Vk7cF?}h0IlZ60lD?Y0mcEm|i@t}xkG`LNfPRpEn0}Ogk$#*0)|_VUX`YCh zXPeiUcbZQypJYD8e46=m^ZDir%@><5HD7MtZ@$m`zWH+tI}4tLk41<@ibaVy2wxNdRZ;;F@77Jpm3wD`y3jm2Bb5tf#gOiO!9mL4d~Er~YM2$x z%G}D*%GxU3D&MNws=;cC)oiQ%R)?&fTD`M&vG%tPwT`n+uuifbXPs?bU|npjw$@lz zT31_7v|eDn$@(Yjd)B{NKeYbc`VR($L1kDm92wD!R7N@@labBHW#lm`8P$whMm?hu zWi&Hz##F{vj2VnsjM7{?hW8K)VS784no0G5%z{ zWxQv6v;j6|Hug3w8;*^WjkishO}LH7CejAAnQybuX0gpuo8>m^Y&O|!w%Ka4-R6|d z8Jlx97i=!s+_br4bI;~in-8{-Eo@7%MTgtk+p=sqwobM@TNhhz+c4X3Taj&~ZKv%7 z+by;`Y;W8C&ZIG|n4!#gW)gE8GnJXn%w#H=)yxKF6SIZc#+=BU#+=Ta$(+la&s@k{ z%v{ab%5^Ro-E z6WE2?jjjT?}ZN+A@1K0v~Fgt`D#tvu4vD4X^>}+-}JC9w!E@GFnHS9`uHM@h2vT=4d zdj@+Jdp3J6dj)$HdkuRXdk6bF_HOoG_A&Nl_7(Ou_Ai{_97~Qh$A-h?a5*jkIH;5(8>CI+{At9L*gA9kU$k949!g zaop~B!118tVaKD6#~e>Mo^rhA_>1FB$J>r~9q&6nKplT`{ODxnAllOF5nt-O}S=VI@f}0#kJ;o zaQ(R=ZVWe$o4`%xrgGD{nOp_8j@!y@=XP>2?gZ{6?iB7c?sV>AZXb6AcNKR%_iOGZ z?q)7}jC+}Tm3y6glY5(cm;03aocn_N5BClCEpG(Rgh%Dkc@{h?o)gcR=gRZodGfq? zp}cUOh!@3+;l=SXc{w~WuYgy?lkzmYDqan*p4Y@{;f?1_;7#OB=FQ`+=B?v>&HIM8 zmG>?0JKi4Nao#E38QwYG1>R-e72Y+J_Y3c-v$^wV=R)Te=OxYuoliQSaz5jH*7=6> zBj+d1&z%2ue&zhe`JKy17ZVpV7rKjui?xf53)3aUCDTRgGSOw8%T|~DF2`L?xtw*m z;BwjJs>^+shc1s?9=rVM@|Vlst}Iu9Ymw_r*R8GxT#vh+aXs&P$@PlsudZ+0U^ki@ z%5ZaVb8&Nb^K|oai*k!`i+4+O8|Rkl*6lXcZI0V~w?%GC-TK^CxNUaZ=C;G_JGUR) zesnwIcHZrh+s|&d-R`OT{^3J>Bfc@8 z%BS-!_#D17-<9vq_u~8V1NZ`d0zaKE;g|B|d?jDQuj1G8>-k;$Dg62TCH!UlKK^Px zx{m)fe-r-z|2Y3={xAGn{JZ>z{NMS1@Sk|nJiRM0`+5g> z2YH8hhj}M>CwY(aPW4{mz219^_jd1{-n+dIcpvmW;(g5fg!f|~nvbtfyib}>rcaJf zo{!9@)JN`9>(k)V?9=Ac>4W)9^O^25(`UBNU7x2u|N6Z5g?tg;;l3k%t$b~K?R;6j zj=m_**Tpy67xVqb_oknjAKx$7FVrvGFTyX{FV-*5Pv)oeEBDj-Rr$61;eI`S6a1$7 zP4}DSH`}k@?_0mCes}$z`n~Y`$M0XikN&X#Fn=R|y1$FRx4)l%pns5mynniXmVd5) zzJHPb2LJ8;2mF8XKjDAc|D697|LguY{qOkSL;e5oe;!~H;2aPUkQgv7AT=O8KoU?9 zP#I7YP#@3~&>GMYFgajq!1REb0Yt#ufcXIn19k^o4tO8P3rq~G3~UN)4eSU+11AQ~ z3Y-&oIq+8CUxBX$KwvCL6pRz33Ni%Q0Qp1TzJ*1@i<81xp0W1uF!r1e*j~1Q!Iq2yO}f34(%7lbiFNFRQdMhk6EIKSMY-!k=8~7P8LoR&JYs9xxxj)#lmI6e&H(NTHyxaCgB$0cHvIpZs9)R z55j}OBf?|ClfpB?^TJEQE5hr-o5DN7`@)C9N5Ut5j_+AEqWz-BYG$L7y(BNix?4M5@8l$9$^(>6JZy@ig1kJ zMYu+IM2w2?iSUmQM2wCIiwKWMiWnD>5|JLUG-5-<#)xkswnjXRcoFd`0(~9vHZm=; zC{h|(5?L0xFmg@gy2uTYnSENL zsC!YrM*SA;6zv`D8|@!0h@KohFM2`rqUfd3m!t1R{~G-;`cVuw#wW%vCLks#rZxtR z!DG5(#>ec9ITmvw=2XntSZb^t8tV|tj&+L7k5$I1V=H1SV-LojjXfWGG4|&;lQ`Qr zyEun9PF!}JEUqk05vPt@6}L5Rd)$t=U2(7Dhs7JkkBm2skBm==Pm9lp&yHUozcYSU z{GRylo>2bZ%(wm|S6Qd~Q;1a&BsFdTwTJVXh*#F1I}w&F#uX zdvhn|&di;iJ1=)Z?xNf!x!>j9%6%fX7PG}};y`h@I6@pPjuR(}GsM|qu{d8`B$kR* z;u>+Qc!GF_m=MnuFAy&luM)2nZxC-3Zx(MA?-3sspB7&i-xog=KN3F?KNG(ZzY~AV z19_CZ;dxGZ33)krop}@TX5=l(TZ`sx$=jZ{GjDg^zPuxO$MR0*oz6R#cOmc3eCvE( z{@DDi{GxnCeqDZhKAPW^-4A1{=NJM`M(t)1^j~11;qvGf~JD5g6ReG3lgFE%;Cf6^<;lEMymY76uju7lsyw7e*8&7LF@S zEle-WEX*#H6e-Gz4wpBC8^ITrDY0*WGv z5{t$ar50rrWfw_`N{Y&g6h-QyilX|W4zy@|5mB_bXjxHz(W;`gMO%ut7ws(CRkXM0 z`=X;oXN#^DJt%rw^t|Y0(d(kO5{kq~Vk|M0&?M#(JBhQzOA;!Hmc&ZpC5e);k}OHC zBwtb}kxEJ=<&q`|F8N9_PqI+5M6z76Lh`lb8_8D5cF9i3F3FFQ6OxOPJCa8d^oit| z5u?lr%&dC5@FPNXJT3q`A_3X^~Val}XE_T4|#cl}?q; zkxgk*=1mlYTATB;73CD%~SJBt0j+CcPoOExjjwAbl!*E`2HeNBXbyUGcDD zvtpZK=VGs7-{OGcpyH6?D6}}XIH5SHIJr2rSX^9ETwdH%j1_kmk1w87JhgaE@%-XN z#Y>8p7xx!$DBe|ksQ6s*wc;Daw~Ox;KPY}${Ji*O@ju1?7QZVQR$@`&P~uVIUm_?O zT@qFzEQv2kDoHL$Ey*a!Dyb@&Te7m`WXYwHnc$m*=pH0vaPaj zWjkfNWP49A6>Qkzo8Qm@jW(vZ?IrJ~ZP z(y^r}rRk-arP-yqXlZTfg3>jmXG*V>-YNaF^q<@(6i?JY6o4E9K>Kt-M-ZCvTUdalDS9>pQWImI=_FN&Lr+lsr2KNNo|{!;v{c&YeD2`P=0HcCe&SLv*DRk|zvl!3}% zR2iZSQ-&+!l&Q)>rCh00s+AQ=t+G+sqHI@oDsg4Ea;kE^vS0a)@;l{j z)D*Rm+E`6hGt^AAgPN^&RCCpy>Ogg*I!T?ZPE%*9bJS9`Of6R{)#Yl9xuw{#N~+dbfJ7`g`?J^;z`|^#k?q>c{G*sQS73t@=YbC`ZbNmyakn zFSjpuDfcfAD;JhWmdBLGm#39ymgkg<%L~ej$`$3+<*nrt%4d|%DxY0Gw|stiU-`=N zHRbEdzb@ZYzO(#L`RVfO<@d`UmOmj}@STQZc-OR^d?LS`kn&rb1K^ zRS{c}P?27dRe|PK>UEA~_z zsyJ0~t>RwAgNolP9#=fAcwOTW{GCGreCuG)oj=7(;U}a&|KDB)%>ElrTIPOc{)~D2`*Jst| z*5}t3);HJV^*!|y>L=ANtY2KetiHc~RsDBphePB(o)t^)l%Ei(9+b>+S1X2 zwk&Gd*YdWN*6QBs*BaOw+#1pv)0*BYZY^k)w3f80S}R&BTWebDTBo(HZ2h72RO{*1 zGp*-Z(VMNeT5q@BZT+M5bsK1-v>CM-w^7>|ZOk@@HclJ2&AH8|EvzlOt-Ywd`^xq`?PuG6ZGYdv=-_t5 zccgTrc1SuZI%+!_I+{D$I=VV~J0^Ba?wH!KzvEiR-yQEdjXI4xsh#vr%T7k8ZKq4; zs7{|w|4u>Ym`+h=RA+2wd}np%($3?Z7do$XKJ0wa`L^=|3Q!7af|{Y`s1?dUIj9qg zx}kw+7%D^~(HL|rnu4aIS!fO_MP+Ce+KzUkK1m# zcc*oWyGy#uy0zW)-7Vb{yC&yAj2J-_xm?s?hs zq1U9B-fP**=(X=<_d50RdPnsNdZT*ddy{&Tdoy~od&Rx^y`{aH-iF@Ey~Kn5DgO^3 C;#4;P diff --git a/source/IJSVG.h b/source/IJSVG.h index e9b90cf..6117b36 100644 --- a/source/IJSVG.h +++ b/source/IJSVG.h @@ -28,6 +28,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject @private IJSVGParser * _group; CGFloat _scale; + CGFloat _clipScale; NSMutableArray * _colors; id _delegate; diff --git a/source/IJSVG.m b/source/IJSVG.m index a08d56e..45dbd38 100644 --- a/source/IJSVG.m +++ b/source/IJSVG.m @@ -211,20 +211,21 @@ static NSColor * _baseColor = nil; // to translate the context so its centered CGFloat tX = round(rect.size.width/2-(_group.size.width/2)*_scale); CGFloat tY = round(rect.size.height/2-(_group.size.height/2)*_scale); - tX -= _group.viewBox.origin.x*_scale; - tY -= _group.viewBox.origin.y*_scale; // we also need to calculate the viewport so we can clip // the drawing if needed NSRect viewPort = NSZeroRect; - viewPort.origin.x = tX; - viewPort.origin.y = tY; - viewPort.size.width = _group.size.width*_scale; - viewPort.size.height = _group.size.height*_scale; + viewPort.origin.x = round(rect.size.width/2-(_group.proposedViewSize.width/2)*_clipScale); + viewPort.origin.y = round(rect.size.height/2-(_group.proposedViewSize.height/2)*_clipScale);; + viewPort.size.width = _group.proposedViewSize.width*_clipScale; + viewPort.size.height = _group.proposedViewSize.height*_clipScale; // clip any drawing to the view port [[NSBezierPath bezierPathWithRect:viewPort] addClip]; + tX -= _group.viewBox.origin.x*_scale; + tY -= _group.viewBox.origin.y*_scale; + CGContextTranslateCTM( ref, tX, tY ); CGContextScaleCTM( ref, _scale, _scale ); @@ -281,7 +282,12 @@ static NSColor * _baseColor = nil; // to transform the paths into our viewbox NSSize dest = rect.size; NSSize source = _group.viewBox.size; - _scale = MIN(dest.width/source.width,dest.height/source.height); + _clipScale = MIN(dest.width/_group.proposedViewSize.width,dest.height/_group.proposedViewSize.height); + + // work out the actual scale based on the clip scale + CGFloat w = _group.proposedViewSize.width*_clipScale; + CGFloat h = _group.proposedViewSize.height*_clipScale; + _scale = MIN(w/source.width,h/source.height); } - (void)_prepClip:(IJSVGNode *)node @@ -412,20 +418,30 @@ static NSColor * _baseColor = nil; // fill the path if( path.fillGradient != nil ) { - if( [path.fillGradient isKindOfClass:[IJSVGLinearGradient class]] ) + CGContextSaveGState(ref); { - // linear gradient - NSGradient * gradient = [path.fillGradient gradient];; - [gradient drawInBezierPath:path.path - angle:path.fillGradient.angle]; - } else if( [path.fillGradient isKindOfClass:[IJSVGRadialGradient class]] ) - { - // radial gradient - // very rudimentary at the moment - IJSVGRadialGradient * radGrad = (IJSVGRadialGradient *)path.fillGradient; - [radGrad.gradient drawInBezierPath:path.path - relativeCenterPosition:NSZeroPoint]; - } + // apply any gradient fill transforms + for( IJSVGTransform * transform in path.gradientTransforms ) + { + [IJSVGTransform performTransform:transform + inContext:ref]; + } + + if( [path.fillGradient isKindOfClass:[IJSVGLinearGradient class]] ) + { + // linear gradient + NSGradient * gradient = [path.fillGradient gradient];; + [gradient drawInBezierPath:path.path + angle:path.fillGradient.angle]; + } else if( [path.fillGradient isKindOfClass:[IJSVGRadialGradient class]] ) + { + // radial gradient + // very rudimentary at the moment + IJSVGRadialGradient * radGrad = (IJSVGRadialGradient *)path.fillGradient; + [radGrad.gradient drawInBezierPath:path.path + relativeCenterPosition:NSZeroPoint]; + } + } CGContextRestoreGState(ref); } else { // no gradient specified // just use the color instead diff --git a/source/IJSVGCommand.h b/source/IJSVGCommand.h index ebc28a1..54fb30a 100644 --- a/source/IJSVGCommand.h +++ b/source/IJSVGCommand.h @@ -55,6 +55,9 @@ typedef NS_ENUM( NSInteger, IJSVGCommandType ) { - (id)initWithCommandString:(NSString *)commandString; ++ (NSPoint)readCoordinatePair:(CGFloat *)pairs + index:(NSInteger)index; + + (void)registerClass:(Class)aClass forCommand:(NSString *)command; + (NSDictionary *)registeredCommandClasses; diff --git a/source/IJSVGCommand.m b/source/IJSVGCommand.m index 2de487c..60eaafa 100644 --- a/source/IJSVGCommand.m +++ b/source/IJSVGCommand.m @@ -90,6 +90,12 @@ static NSMutableDictionary * _classes = nil; return self; } ++ (NSPoint)readCoordinatePair:(CGFloat *)pairs + index:(NSInteger)index +{ + return NSMakePoint( pairs[index*2], pairs[index*2+1]); +} + + (void)registerClass:(Class)aClass forCommand:(NSString *)command { diff --git a/source/IJSVGCommandArc.m b/source/IJSVGCommandArc.m index 9d01578..1ed1c9e 100644 --- a/source/IJSVGCommandArc.m +++ b/source/IJSVGCommandArc.m @@ -27,7 +27,27 @@ type:(IJSVGCommandType)type path:(IJSVGPath *)path { - +// NSPoint point = [path currentPoint]; +// +// CGFloat x1 = point.x; +// CGFloat y1 = point.y; +// +// NSPoint radii = [[self class] readCoordinatePair:params +// index:0]; +// +// CGFloat rX = fabs(radii.x); +// CGFloat rY = fabs(radii.y); +// +// CGFloat phi = params[2]; +// phi *= M_PI/180; +// +// BOOL largeArcFlag = params[3] != 0.f; +// BOOL sweepFlag = params[4] != 0.f; +// +// NSPoint endPoint = NSMakePoint( params[5], params[6]); +// +// CGFloat x2 = point.x + endPoint.x; +// CGFloat y2 = point.y + endPoint.y; } @end diff --git a/source/IJSVGGradient.m b/source/IJSVGGradient.m index fbda625..9f8f293 100644 --- a/source/IJSVGGradient.m +++ b/source/IJSVGGradient.m @@ -19,6 +19,13 @@ [super dealloc]; } +- (id)copyWithZone:(NSZone *)zone +{ + IJSVGGradient * clone = [super copyWithZone:zone]; + clone.gradient = [[self.gradient copy] autorelease]; + return clone; +} + + (CGFloat *)computeColorStopsFromString:(NSXMLElement *)element colors:(NSArray **)someColors { diff --git a/source/IJSVGLinearGradient.m b/source/IJSVGLinearGradient.m index e42b1dc..d7bc0a5 100644 --- a/source/IJSVGLinearGradient.m +++ b/source/IJSVGLinearGradient.m @@ -33,10 +33,14 @@ aGradient.angle = [IJSVGUtils angleBetweenPointA:NSMakePoint( x1, y1 ) pointb:NSMakePoint( x2, y2 )]; + if( aGradient.gradient != nil ) + return nil; + // compute the color stops and colours NSArray * colors = nil; CGFloat * stopsParams = [[self class] computeColorStopsFromString:element colors:&colors]; + // create the gradient with the colours NSGradient * grad = [[[NSGradient alloc] initWithColors:colors atLocations:stopsParams diff --git a/source/IJSVGNode.h b/source/IJSVGNode.h index 60e52f8..37614c6 100644 --- a/source/IJSVGNode.h +++ b/source/IJSVGNode.h @@ -83,6 +83,7 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991; IJSVGNode * parentNode; IJSVGGroup * clipPath; NSArray * transforms; + NSArray * gradientTransforms; IJSVGWindingRule windingRule; IJSVGLineCapStyle lineCapStyle; @@ -112,6 +113,7 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991; @property ( nonatomic, assign ) IJSVGLineCapStyle lineCapStyle; @property ( nonatomic, assign ) IJSVGLineJoinStyle lineJoinStyle; @property ( nonatomic, retain ) NSArray * transforms; +@property ( nonatomic, retain ) NSArray * gradientTransforms; @property ( nonatomic, retain ) IJSVGDef * def; @property ( nonatomic, retain ) IJSVGGradient * fillGradient; @property ( nonatomic, assign ) CGFloat * strokeDashArray; @@ -120,6 +122,7 @@ static CGFloat IJSVGInheritedFloatValue = -99.9999991; + (IJSVGNodeType)typeForString:(NSString *)string; +- (void)applyPropertiesFromNode:(IJSVGNode *)node; - (id)initWithDef:(BOOL)flag; - (void)addDef:(IJSVGNode *)aDef; - (IJSVGDef *)defForID:(NSString *)anID; diff --git a/source/IJSVGNode.m b/source/IJSVGNode.m index 48932d8..29959f0 100644 --- a/source/IJSVGNode.m +++ b/source/IJSVGNode.m @@ -26,6 +26,7 @@ @synthesize identifier; @synthesize parentNode; @synthesize transforms; +@synthesize gradientTransforms; @synthesize windingRule; @synthesize def; @synthesize fillGradient; @@ -42,6 +43,7 @@ free(strokeDashArray); [fillGradient release], fillGradient = nil; [transforms release], transforms = nil; + [gradientTransforms release], gradientTransforms = nil; [fillColor release], fillColor = nil; [strokeColor release], strokeColor = nil; [identifier release], identifier = nil; @@ -90,45 +92,50 @@ return self; } -- (id)copyWithZone:(NSZone *)zone +- (void)applyPropertiesFromNode:(IJSVGNode *)node { - IJSVGNode * node = [[self class] allocWithZone:zone]; - node.name = self.name; - node.type = self.type; + self.name = node.name; + self.type = node.type; - node.x = self.x; - node.y = self.y; - node.width = self.width; - node.height = self.height; + self.x = node.x; + self.y = node.y; + self.width = node.width; + self.height = node.height; - node.fillGradient = self.fillGradient; + self.fillGradient = node.fillGradient; - node.fillColor = self.fillColor; - node.strokeColor = self.strokeColor; - node.clipPath = self.clipPath; + self.fillColor = node.fillColor; + self.strokeColor = node.strokeColor; + self.clipPath = node.clipPath; - node.opacity = self.opacity; - node.strokeWidth = self.strokeWidth; - node.fillOpacity = self.fillOpacity; - node.strokeOpacity = self.strokeOpacity; + self.opacity = node.opacity; + self.strokeWidth = node.strokeWidth; + self.fillOpacity = node.fillOpacity; + self.strokeOpacity = node.strokeOpacity; - node.identifier = self.identifier; - node.usesDefaultFillColor = self.usesDefaultFillColor; + self.identifier = node.identifier; + self.usesDefaultFillColor = node.usesDefaultFillColor; - node.transforms = self.transforms; - node.def = self.def; - node.windingRule = self.windingRule; - node.lineCapStyle = self.lineCapStyle; - node.lineJoinStyle = self.lineJoinStyle; - node.parentNode = self.parentNode; + self.transforms = node.transforms; + self.gradientTransforms = node.gradientTransforms; + self.def = node.def; + self.windingRule = node.windingRule; + self.lineCapStyle = node.lineCapStyle; + self.lineJoinStyle = node.lineJoinStyle; + self.parentNode = node.parentNode; // dash array needs physical memory copied CGFloat * nStrokeDashArray = (CGFloat *)malloc(node.strokeDashArrayCount*sizeof(CGFloat)); memcpy( self.strokeDashArray, nStrokeDashArray, node.strokeDashArrayCount*sizeof(CGFloat)); - node.strokeDashArray = nStrokeDashArray; - node.strokeDashArrayCount = self.strokeDashArrayCount; - node.strokeDashOffset = self.strokeDashOffset; - + self.strokeDashArray = nStrokeDashArray; + self.strokeDashArrayCount = node.strokeDashArrayCount; + self.strokeDashOffset = node.strokeDashOffset; +} + +- (id)copyWithZone:(NSZone *)zone +{ + IJSVGNode * node = [[self class] allocWithZone:zone]; + [node applyPropertiesFromNode:self]; return node; } diff --git a/source/IJSVGParser.h b/source/IJSVGParser.h index a178c40..1b80ed8 100644 --- a/source/IJSVGParser.h +++ b/source/IJSVGParser.h @@ -34,6 +34,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject @interface IJSVGParser : IJSVGGroup { NSRect viewBox; + NSSize proposedViewSize; @private id _delegate; @@ -42,6 +43,7 @@ handleForeignObject:(IJSVGForeignObject *)foreignObject } @property ( nonatomic, readonly ) NSRect viewBox; +@property ( nonatomic, readonly ) NSSize proposedViewSize; - (id)initWithFileURL:(NSURL *)aURL delegate:(id)delegate; diff --git a/source/IJSVGParser.m b/source/IJSVGParser.m index fae8e69..0e803aa 100644 --- a/source/IJSVGParser.m +++ b/source/IJSVGParser.m @@ -11,6 +11,7 @@ @implementation IJSVGParser @synthesize viewBox; +@synthesize proposedViewSize; + (IJSVGParser *)groupForFileURL:(NSURL *)aURL { @@ -98,6 +99,15 @@ viewBox = NSMakeRect( 0.f, 0.f, w, h ); } + CGFloat w = [[[svgElement attributeForName:@"width"] stringValue] floatValue]; + CGFloat h = [[[svgElement attributeForName:@"height"] stringValue] floatValue]; + if( w == 0.f && h == 0.f ) + { + w = viewBox.size.width; + h = viewBox.size.height; + } + proposedViewSize = NSMakeSize( w, h ); + // find foreign objects... NSXMLElement * switchElement = nil; NSArray * switchElements = [svgElement nodesForXPath:@"switch" @@ -260,6 +270,17 @@ node.transforms = tran; } + // gradient transforms + NSXMLNode * gradTransformAttribute = [element attributeForName:@"gradientTransform"]; + if( gradTransformAttribute != nil ) + { + NSMutableArray * tran = [[[NSMutableArray alloc] init] autorelease]; + [tran addObjectsFromArray:[IJSVGTransform transformsForString:[gradTransformAttribute stringValue]]]; + if( node.gradientTransforms != nil ) + [tran addObjectsFromArray:node.gradientTransforms]; + node.gradientTransforms = tran; + } + // winding rule NSXMLNode * windingRuleAttribute = [element attributeForName:@"fill-rule"]; if( windingRuleAttribute != nil ) @@ -606,6 +627,24 @@ // linear gradient case IJSVGNodeTypeLinearGradient: { + NSString * xlink = [[element attributeForName:@"xlink:href"] stringValue]; + NSString * xlinkID = [xlink substringFromIndex:1]; + IJSVGNode * node = [parentGroup defForID:xlinkID]; + if( node != nil ) + { + // we are a clone + IJSVGLinearGradient * grad = [[[IJSVGLinearGradient alloc] init] autorelease]; + grad.type = aType; + [grad applyPropertiesFromNode:node]; + grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease]; + [IJSVGLinearGradient parseGradient:element + gradient:grad]; + [self _parseElementForCommonAttributes:element + node:grad]; + [parentGroup addDef:grad]; + continue; + } + IJSVGLinearGradient * gradient = [[[IJSVGLinearGradient alloc] init] autorelease]; gradient.type = aType; gradient.gradient = [IJSVGLinearGradient parseGradient:element @@ -618,6 +657,25 @@ // radial gradient case IJSVGNodeTypeRadialGradient: { + + NSString * xlink = [[element attributeForName:@"xlink:href"] stringValue]; + NSString * xlinkID = [xlink substringFromIndex:1]; + IJSVGNode * node = [parentGroup defForID:xlinkID]; + if( node != nil ) + { + // we are a clone + IJSVGRadialGradient * grad = [[[IJSVGRadialGradient alloc] init] autorelease]; + grad.type = aType; + [grad applyPropertiesFromNode:node]; + grad.gradient = [[[(IJSVGGradient *)node gradient] copy] autorelease]; + [IJSVGRadialGradient parseGradient:element + gradient:grad]; + [self _parseElementForCommonAttributes:element + node:grad]; + [parentGroup addDef:grad]; + continue; + } + IJSVGRadialGradient * gradient = [[[IJSVGRadialGradient alloc] init] autorelease]; gradient.type = aType; gradient.gradient = [IJSVGRadialGradient parseGradient:element diff --git a/source/IJSVGRadialGradient.m b/source/IJSVGRadialGradient.m index 865ca21..a3e4635 100644 --- a/source/IJSVGRadialGradient.m +++ b/source/IJSVGRadialGradient.m @@ -16,6 +16,7 @@ @synthesize fy; @synthesize radius; + + (NSGradient *)parseGradient:(NSXMLElement *)element gradient:(IJSVGRadialGradient *)gradient { @@ -39,6 +40,9 @@ gradient.fy = .5; } + if( gradient.gradient != nil ) + return nil; + NSArray * colors = nil; CGFloat * colorStops = [[self class] computeColorStopsFromString:element colors:&colors]; NSGradient * ret = [[[NSGradient alloc] initWithColors:colors diff --git a/source/IJSVGUtils.m b/source/IJSVGUtils.m index 2f520b1..e82a908 100644 --- a/source/IJSVGUtils.m +++ b/source/IJSVGUtils.m @@ -174,7 +174,7 @@ } + (CGFloat)floatValue:(NSString *)string - fallBackForPercent:(CGFloat)fallBack + fallBackForPercent:(CGFloat)fallBack { CGFloat val = [string floatValue]; if( [string rangeOfString:@"%"].location != NSNotFound )